예제 #1
0
 /**
  * Multiply two arbitrary precision number
  *
  * @param string $a The left operand, as a string.
  * @param string $b The right operand, as a string.
  * @access public
  * @return string Returns the result as a string.
  */
 public function mul($a, $b)
 {
     $a = new Math_BigInteger($a);
     $b = new Math_BigInteger($b);
     $c = $a->multiply($b);
     return $c->toString();
 }
예제 #2
0
 protected static function make64Int($hi, $lo)
 {
     if (PHP_INT_SIZE > 4) {
         return (int) $hi << 32 | (int) $lo;
     }
     $lo = sprintf("%u", $lo);
     if (function_exists("gmp_mul")) {
         return gmp_strval(gmp_add(gmp_mul($hi, "4294967296"), $lo));
     }
     if (function_exists("bcmul")) {
         return bcadd(bcmul($hi, "4294967296"), $lo);
     }
     if (class_exists('Math_BigInteger')) {
         $bi = new Math_BigInteger($hi);
         return $bi->multiply("4294967296")->add($lo)->toString();
     }
     throw new PListException("either gmp or bc has to be installed, or the Math_BigInteger has to be available!");
 }
예제 #3
0
 /**
  * @param string $ip IPv4 or IPv6 address to convert
  * @return string 128bit string that can be used with DECIMNAL(39,0) or false
  */
 public static function inet_ptoi($ip)
 {
     // make sure it is an ip
     if (filter_var($ip, FILTER_VALIDATE_IP) === false) {
         return false;
     }
     $parts = unpack('N*', inet_pton($ip));
     // fix IPv4
     if (strpos($ip, '.') !== false) {
         $parts = array(1 => 0, 2 => 0, 3 => 0, 4 => $parts[1]);
     }
     foreach ($parts as &$part) {
         // convert any unsigned ints to signed from unpack.
         // this should be OK as it will be a PHP float not an int
         if ($part < 0) {
             $part = 4294967296.0;
         }
     }
     if (function_exists('bcadd')) {
         // Use BCMath if available
         $decimal = $parts[4];
         $decimal = bcadd($decimal, bcmul($parts[3], '4294967296'));
         $decimal = bcadd($decimal, bcmul($parts[2], '18446744073709551616'));
         $decimal = bcadd($decimal, bcmul($parts[1], '79228162514264337593543950336'));
     } else {
         // Otherwise use the pure PHP BigInteger class
         $decimal = new Math_BigInteger($parts[4]);
         $partTree = new Math_BigInteger($parts[3]);
         $partTwo = new Math_BigInteger($parts[2]);
         $partOne = new Math_BigInteger($parts[1]);
         $decimal = $decimal->add($partTree->multiply(new Math_BigInteger('4294967296')));
         $decimal = $decimal->add($partTwo->multiply(new Math_BigInteger('18446744073709551616')));
         $decimal = $decimal->add($partOne->multiply(new Math_BigInteger('79228162514264337593543950336')));
         $decimal = $decimal->toString();
     }
     return $decimal;
 }
예제 #4
0
파일: IPv6.php 프로젝트: atwardowski/gixlg
 function inet_ptoi($ip)
 {
     // make sure it is an ip
     if (filter_var($ip, FILTER_VALIDATE_IP) === false) {
         return false;
     }
     $parts = unpack('N*', inet_pton($ip));
     // fix IPv4
     if (strpos($ip, '.') !== false) {
         $parts = array(1 => 0, 2 => 0, 3 => 0, 4 => $parts[1]);
     }
     foreach ($parts as &$part) {
         // convert any unsigned ints to signed from unpack.
         // this should be OK as it will be a PHP float not an int
         if ($part < 0) {
             $part += 4294967296;
         }
     }
     // use BCMath if the extension exists
     if (function_exists('bcadd')) {
         $decimal = $parts[4];
         $decimal = bcadd($decimal, bcmul($parts[3], '4294967296'));
         $decimal = bcadd($decimal, bcmul($parts[2], '18446744073709551616'));
         $decimal = bcadd($decimal, bcmul($parts[1], '79228162514264337593543950336'));
     } else {
         $decimal = new Math_BigInteger($parts[4]);
         $part3 = new Math_BigInteger($parts[3]);
         $part2 = new Math_BigInteger($parts[2]);
         $part1 = new Math_BigInteger($parts[1]);
         $decimal = $decimal->add($part3->multiply(new Math_BigInteger('4294967296')));
         $decimal = $decimal->add($part2->multiply(new Math_BigInteger('18446744073709551616')));
         $decimal = $decimal->add($part1->multiply(new Math_BigInteger('79228162514264337593543950336')));
         $decimal = $decimal->toString();
     }
     return $decimal;
 }
예제 #5
0
 /**
  * Calculates the greatest common divisor and Bezout's identity.
  *
  * Say you have 693 and 609.  The GCD is 21.  Bezout's identity states that there exist integers x and y such that
  * 693*x + 609*y == 21.  In point of fact, there are actually an infinite number of x and y combinations and which
  * combination is returned is dependant upon which mode is in use.  See
  * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information.
  *
  * Here's an example:
  * <code>
  * <?php
  *    include 'Math/BigInteger.php';
  *
  *    $a = new Math_BigInteger(693);
  *    $b = new Math_BigInteger(609);
  *
  *    extract($a->extendedGCD($b));
  *
  *    echo $gcd->toString() . "\r\n"; // outputs 21
  *    echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21
  * ?>
  * </code>
  *
  * @param Math_BigInteger $n
  * @return Math_BigInteger
  * @access public
  * @internal Calculates the GCD using the binary xGCD algorithim described in
  *    {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}.  As the text above 14.61 notes,
  *    the more traditional algorithim requires "relatively costly multiple-precision divisions".
  */
 function extendedGCD($n)
 {
     switch (MATH_BIGINTEGER_MODE) {
         case MATH_BIGINTEGER_MODE_GMP:
             extract(gmp_gcdext($this->value, $n->value));
             return array('gcd' => $this->_normalize(new Math_BigInteger($g)), 'x' => $this->_normalize(new Math_BigInteger($s)), 'y' => $this->_normalize(new Math_BigInteger($t)));
         case MATH_BIGINTEGER_MODE_BCMATH:
             // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works
             // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway.  as is,
             // the basic extended euclidean algorithim is what we're using.
             $u = $this->value;
             $v = $n->value;
             $a = '1';
             $b = '0';
             $c = '0';
             $d = '1';
             while (bccomp($v, '0', 0) != 0) {
                 $q = bcdiv($u, $v, 0);
                 $temp = $u;
                 $u = $v;
                 $v = bcsub($temp, bcmul($v, $q, 0), 0);
                 $temp = $a;
                 $a = $c;
                 $c = bcsub($temp, bcmul($a, $q, 0), 0);
                 $temp = $b;
                 $b = $d;
                 $d = bcsub($temp, bcmul($b, $q, 0), 0);
             }
             return array('gcd' => $this->_normalize(new Math_BigInteger($u)), 'x' => $this->_normalize(new Math_BigInteger($a)), 'y' => $this->_normalize(new Math_BigInteger($b)));
     }
     $y = $n->copy();
     $x = $this->copy();
     $g = new Math_BigInteger();
     $g->value = array(1);
     while (!($x->value[0] & 1 || $y->value[0] & 1)) {
         $x->_rshift(1);
         $y->_rshift(1);
         $g->_lshift(1);
     }
     $u = $x->copy();
     $v = $y->copy();
     $a = new Math_BigInteger();
     $b = new Math_BigInteger();
     $c = new Math_BigInteger();
     $d = new Math_BigInteger();
     $a->value = $d->value = $g->value = array(1);
     $b->value = $c->value = array();
     while (!empty($u->value)) {
         while (!($u->value[0] & 1)) {
             $u->_rshift(1);
             if (!empty($a->value) && $a->value[0] & 1 || !empty($b->value) && $b->value[0] & 1) {
                 $a = $a->add($y);
                 $b = $b->subtract($x);
             }
             $a->_rshift(1);
             $b->_rshift(1);
         }
         while (!($v->value[0] & 1)) {
             $v->_rshift(1);
             if (!empty($d->value) && $d->value[0] & 1 || !empty($c->value) && $c->value[0] & 1) {
                 $c = $c->add($y);
                 $d = $d->subtract($x);
             }
             $c->_rshift(1);
             $d->_rshift(1);
         }
         if ($u->compare($v) >= 0) {
             $u = $u->subtract($v);
             $a = $a->subtract($c);
             $b = $b->subtract($d);
         } else {
             $v = $v->subtract($u);
             $c = $c->subtract($a);
             $d = $d->subtract($b);
         }
     }
     return array('gcd' => $this->_normalize($g->multiply($v)), 'x' => $this->_normalize($c), 'y' => $this->_normalize($d));
 }
예제 #6
0
파일: biginteger.php 프로젝트: thu0ng91/jmc
 /**
  * Divides two BigIntegers.
  *
  * Returns an array whose first element contains the quotient and whose second element contains the
  * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the
  * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder
  * and the divisor.
  *
  * Here's a quick 'n dirty example:
  * <code>
  * <?php
  *    include('Math/BigInteger.php');
  *
  *    $a = new Math_BigInteger('10');
  *    $b = new Math_BigInteger('20');
  *
  *    list($quotient,$remainder) = $a->divide($b);
  *
  *    echo $quotient->toString(); // outputs 0
  *    echo "\r\n";
  *    echo $remainder->toString(); // outputs 10
  * ?>
  * </code>
  *
  * @param Math_BigInteger $y
  * @return Array
  * @access public
  * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}
  *    with a slight variation due to the fact that this script, initially, did not support negative numbers.  Now,
  *    it does, but I don't want to change that which already works.
  */
 function divide($y)
 {
     switch (MATH_BIGINTEGER_MODE) {
         case MATH_BIGINTEGER_MODE_GMP:
             $quotient = new Math_BigInteger();
             $remainder = new Math_BigInteger();
             list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
             if (gmp_sign($remainder->value) < 0) {
                 $remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
             }
             return array($quotient, $remainder);
         case MATH_BIGINTEGER_MODE_BCMATH:
             $quotient = new Math_BigInteger();
             $remainder = new Math_BigInteger();
             $quotient->value = bcdiv($this->value, $y->value);
             $remainder->value = bcmod($this->value, $y->value);
             if ($remainder->value[0] == '-') {
                 $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value);
             }
             return array($quotient, $remainder);
     }
     $x = $this->_copy();
     $y = $y->_copy();
     $x_sign = $x->is_negative;
     $y_sign = $y->is_negative;
     $x->is_negative = $y->is_negative = false;
     $diff = $x->compare($y);
     if (!$diff) {
         $temp = new Math_BigInteger();
         $temp->value = array(1);
         $temp->is_negative = $x_sign != $y_sign;
         return array($temp, new Math_BigInteger());
     }
     if ($diff < 0) {
         // if $x is negative, "add" $y.
         if ($x_sign) {
             $x = $y->subtract($x);
         }
         return array(new Math_BigInteger(), $x);
     }
     // normalize $x and $y as described in HAC 14.23 / 14.24
     // (incidently, i haven't been able to find a definitive example showing that this
     // results in worth-while speedup, but whatever)
     $msb = $y->value[count($y->value) - 1];
     for ($shift = 0; !($msb & 0x2000000); $shift++) {
         $msb <<= 1;
     }
     $x->_lshift($shift);
     $y->_lshift($shift);
     $x_max = count($x->value) - 1;
     $y_max = count($y->value) - 1;
     $quotient = new Math_BigInteger();
     $quotient->value = $this->_array_repeat(0, $x_max - $y_max + 1);
     // $temp = $y << ($x_max - $y_max-1) in base 2**26
     $temp = new Math_BigInteger();
     $temp->value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y->value);
     while ($x->compare($temp) >= 0) {
         // calculate the "common residue"
         $quotient->value[$x_max - $y_max]++;
         $x = $x->subtract($temp);
         $x_max = count($x->value) - 1;
     }
     for ($i = $x_max; $i >= $y_max + 1; $i--) {
         $x_value = array($x->value[$i], $i > 0 ? $x->value[$i - 1] : 0, $i - 1 > 0 ? $x->value[$i - 2] : 0);
         $y_value = array($y->value[$y_max], $y_max > 0 ? $y_max - 1 : 0);
         $q_index = $i - $y_max - 1;
         if ($x_value[0] == $y_value[0]) {
             $quotient->value[$q_index] = 0x3ffffff;
         } else {
             $quotient->value[$q_index] = floor(($x_value[0] * 0x4000000 + $x_value[1]) / $y_value[0]);
         }
         $temp = new Math_BigInteger();
         $temp->value = array($y_value[1], $y_value[0]);
         $lhs = new Math_BigInteger();
         $lhs->value = array($quotient->value[$q_index]);
         $lhs = $lhs->multiply($temp);
         $rhs = new Math_BigInteger();
         $rhs->value = array($x_value[2], $x_value[1], $x_value[0]);
         while ($lhs->compare($rhs) > 0) {
             $quotient->value[$q_index]--;
             $lhs = new Math_BigInteger();
             $lhs->value = array($quotient->value[$q_index]);
             $lhs = $lhs->multiply($temp);
         }
         $corrector = new Math_BigInteger();
         $temp = new Math_BigInteger();
         $corrector->value = $temp->value = $this->_array_repeat(0, $q_index);
         $temp->value[] = $quotient->value[$q_index];
         $temp = $temp->multiply($y);
         if ($x->compare($temp) < 0) {
             $corrector->value[] = 1;
             $x = $x->add($corrector->multiply($y));
             $quotient->value[$q_index]--;
         }
         $x = $x->subtract($temp);
         $x_max = count($x->value) - 1;
     }
     // unnormalize the remainder
     $x->_rshift($shift);
     $quotient->is_negative = $x_sign != $y_sign;
     // calculate the "common residue", if appropriate
     if ($x_sign) {
         $y->_rshift($shift);
         $x = $y->subtract($x);
     }
     return array($quotient->_normalize(), $x);
 }
예제 #7
0
파일: DSA.php 프로젝트: raz0rsdge/horde
 /**
  * DSA verify.
  *
  * @param string $message     Message.
  * @param string $hash_alg    Hash algorithm.
  * @param Math_BigInteger $r  r.
  * @param Math_BigInteger $s  s.
  *
  * @return bool  True if verified.
  */
 public function verify($message, $hash_alg, $r, $s)
 {
     $hash = new Crypt_Hash($hash_alg);
     $hash_m = new Math_BigInteger($hash->hash($message), 256);
     $g = new Math_BigInteger($this->_key->key['g'], 256);
     $p = new Math_BigInteger($this->_key->key['p'], 256);
     $q = new Math_BigInteger($this->_key->key['q'], 256);
     $y = new Math_BigInteger($this->_key->key['y'], 256);
     $w = $s->modInverse($q);
     $hash_m_mul = $hash_m->multiply($w);
     $u1_base = $hash_m_mul->divide($q);
     $u1 = $u1_base[1];
     $r_mul = $r->multiply($w);
     $u2_base = $r_mul->divide($q);
     $u2 = $u2_base[1];
     $g_pow = $g->modPow($u1, $p);
     $y_pow = $y->modPow($u2, $p);
     $g_pow_mul = $g_pow->multiply($y_pow);
     $g_pow_mul_mod_base = $g_pow_mul->divide($p);
     $g_pow_mul_mod = $g_pow_mul_mod_base[1];
     $v_base = $g_pow_mul_mod->divide($q);
     $v = $v_base[1];
     return $v->compare($r) == 0;
 }
 /**
  * Create an 64 bit integer using bcmath or gmp
  * @param int $hi The higher word
  * @param int $lo The lower word
  * @return mixed The integer (as int if possible, as string if not possible)
  * @throws PListException if neither gmp nor bc available
  */
 protected static function make64Int($hi, $lo)
 {
     // on x64, we can just use int
     if (PHP_INT_SIZE > 4) {
         return (int) $hi << 32 | (int) $lo;
     }
     // lower word has to be unsigned since we don't use bitwise or, we use bcadd/gmp_add
     $lo = sprintf("%u", $lo);
     // use GMP or bcmath if possible
     if (function_exists("gmp_mul")) {
         return gmp_strval(gmp_add(gmp_mul($hi, "4294967296"), $lo));
     }
     if (function_exists("bcmul")) {
         return bcadd(bcmul($hi, "4294967296"), $lo);
     }
     if (class_exists('Math_BigInteger')) {
         $bi = new \Math_BigInteger($hi);
         return $bi->multiply(new \Math_BigInteger("4294967296"))->add(new \Math_BigInteger($lo))->toString();
     }
     throw new PListException("either gmp or bc has to be installed, or the Math_BigInteger has to be available!");
 }
예제 #9
0
$result = bcsub($result, $y);
$_result = $_result->subtract($_y);
echo "\$result = \$result-\$y;\r\n";
echo "{$result}\r\n";
echo $_result->toString();
echo "\r\n\r\n";
$result = bcdiv($x, $y);
list($_result, ) = $_x->divide($_y);
echo "\$result = \$x/\$y;\r\n";
echo "{$result}\r\n";
echo $_result->toString();
echo "\r\n\r\n";
$result = bcmod($y, $z);
list(, $_result) = $_y->divide($_z);
echo "\$result = \$x%\$y;\r\n";
echo "{$result}\r\n";
echo $_result->toString();
echo "\r\n\r\n";
$result = bcmul($x, $z);
$_result = $_x->multiply($_z);
echo "\$result = \$x*\$z;\r\n";
echo "{$result}\r\n";
echo $_result->toString();
echo "\r\n\r\n";
$result = bcpowmod($x, $y, $result);
$_result = $_x->modPow($_y, $_result);
echo "\$result = (\$x**\$y)%\$result;\r\n";
echo "{$result}\r\n";
echo $_result->toString();
echo "\r\n\r\n";
// modInverse isn't demo'd because no equivalent to it exists in BCMath.
예제 #10
0
 public function extendedGCD($n)
 {
     switch (MATH_BIGINTEGER_MODE) {
         case MATH_BIGINTEGER_MODE_GMP:
             $_gmp_gcdext = gmp_gcdext($this->value, $n->value);
             $g = $_gmp_gcdext['g'];
             $s = $_gmp_gcdext['s'];
             $t = $_gmp_gcdext['t'];
             return array('gcd' => $this->_normalize(new Math_BigInteger($g)), 'x' => $this->_normalize(new Math_BigInteger($s)), 'y' => $this->_normalize(new Math_BigInteger($t)));
         case MATH_BIGINTEGER_MODE_BCMATH:
             $u = $this->value;
             $v = $n->value;
             $a = '1';
             $b = '0';
             $c = '0';
             $d = '1';
             while (bccomp($v, '0', 0) != 0) {
                 $q = bcdiv($u, $v, 0);
                 $temp = $u;
                 $u = $v;
                 $v = bcsub($temp, bcmul($v, $q, 0), 0);
                 $temp = $a;
                 $a = $c;
                 $c = bcsub($temp, bcmul($a, $q, 0), 0);
                 $temp = $b;
                 $b = $d;
                 $d = bcsub($temp, bcmul($b, $q, 0), 0);
             }
             return array('gcd' => $this->_normalize(new Math_BigInteger($u)), 'x' => $this->_normalize(new Math_BigInteger($a)), 'y' => $this->_normalize(new Math_BigInteger($b)));
     }
     $y = $n->copy();
     $x = $this->copy();
     $g = new Math_BigInteger();
     $g->value = array(1);
     while (!($x->value[0] & 1 || $y->value[0] & 1)) {
         $x->_rshift(1);
         $y->_rshift(1);
         $g->_lshift(1);
     }
     $u = $x->copy();
     $v = $y->copy();
     $a = new Math_BigInteger();
     $b = new Math_BigInteger();
     $c = new Math_BigInteger();
     $d = new Math_BigInteger();
     $a->value = $d->value = $g->value = array(1);
     $b->value = $c->value = array();
     while (!empty($u->value)) {
         while (!($u->value[0] & 1)) {
             $u->_rshift(1);
             if (!empty($a->value) && $a->value[0] & 1 || !empty($b->value) && $b->value[0] & 1) {
                 $a = $a->add($y);
                 $b = $b->subtract($x);
             }
             $a->_rshift(1);
             $b->_rshift(1);
         }
         while (!($v->value[0] & 1)) {
             $v->_rshift(1);
             if (!empty($d->value) && $d->value[0] & 1 || !empty($c->value) && $c->value[0] & 1) {
                 $c = $c->add($y);
                 $d = $d->subtract($x);
             }
             $c->_rshift(1);
             $d->_rshift(1);
         }
         if (0 <= $u->compare($v)) {
             $u = $u->subtract($v);
             $a = $a->subtract($c);
             $b = $b->subtract($d);
         } else {
             $v = $v->subtract($u);
             $c = $c->subtract($a);
             $d = $d->subtract($b);
         }
     }
     return array('gcd' => $this->_normalize($g->multiply($v)), 'x' => $this->_normalize($c), 'y' => $this->_normalize($d));
 }
예제 #11
0
 /**
  * Converts human readable representation to a 128bit int
  * which can be stored in MySQL using DECIMAL(39,0).
  *
  * Requires PHP to be compiled with IPv6 support.
  * This could be made to work without IPv6 support but
  * I don't think there would be much use for it if PHP
  * doesn't support IPv6.
  *
  * @author Sam Clarke
  * @link http://www.samclarke.com/2011/07/php-ipv6-to-128bit-int/
  * @param string $ip IPv4 or IPv6 address to convert
  * @return string 128bit string that can be used with DECIMNAL(39,0) or false
  */
 protected static function ipToDecimal($ip)
 {
     // make sure it is an ip
     if (filter_var($ip, FILTER_VALIDATE_IP) === false) {
         throw new NotValidIpException($ip);
     }
     $parts = unpack('N*', inet_pton($ip));
     // fix IPv4
     if (strpos($ip, '.') !== false) {
         $parts = array(1 => 0, 2 => 0, 3 => 0, 4 => $parts[1]);
     }
     foreach ($parts as &$part) {
         // convert any unsigned ints to signed from unpack.
         // this should be OK as it will be a PHP float not an int
         if ($part < 0) {
             $part = 4294967296;
         }
     }
     $decimal = new BigInteger($parts[4]);
     $part3 = new BigInteger($parts[3]);
     $part2 = new BigInteger($parts[2]);
     $part1 = new BigInteger($parts[1]);
     $decimal = $decimal->add($part3->multiply(new BigInteger('4294967296')));
     $decimal = $decimal->add($part2->multiply(new BigInteger('18446744073709551616')));
     $decimal = $decimal->add($part1->multiply(new BigInteger('79228162514264337593543950336')));
     $decimal = $decimal->toString();
     return $decimal;
 }