This commit is contained in:
2025-10-09 17:41:57 +00:00
commit 7a3b2960f8
146 changed files with 34948 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
## MIT LICENSE
Copyright (C) 2018 Simplito
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+190
View File
@@ -0,0 +1,190 @@
# BigInteger wrapper library for PHP
## Information
This library is a common interface for php_gmp and php_bcmath modules. It automatically detects supported modules and uses the best of them (gmp>bcmath). Gmp is a lot faster, but is also missing on many hosting services -- that is why this wrapper has been created. It is used for example in encryption functions of the [PrivMX WebMail](https://privmx.com) software.
## Installation
You can install this library via Composer:
```
composer require simplito/bigint-wrapper-php
```
## Documentation
If you want to force using a specific implementation, then define constant S_MATH_BIGINTEGER_MODE - set it to "gmp" or "bcmath". If you do not do this, mode of operation and the constant will be set automatically.
If there are no gmp and bcmath modules, an exception will be thrown. If you want to prevent this, then simply define S_MATH_BIGINTEGER_QUIET constant.
All functions of this library are implemented as members of class BigInteger, which is located under BI namespace. Instances of BigInteger are immutable - member functions usually return new instances of the BigInteger class.
### ConvertibleToBi - a placeholder type
To make the below documentation more readable we use the "ConvertibleToBi" type symbol, which in reality can be one of the following types:
- an instance of the BigInteger class
- an integer
- a decimal string
- a gmp resource or class (only when you are in gmp mode)
If you have a non-decimal string and want to use it -- first you have to convert it to BigInteger class using:
```
new BigInteger($myNonDecimalString, $baseOfMyNonDecimalString)
```
### BI\BigInteger class members
#### construct(ConvertibleToBi $value = 0, int $base = 10)
Creates a new instance of BigInteger. If you pass an invalid value, an exception will be thrown. If $base === true then passed $value will be used without any check and conversion. Supported bases: 2, 10, 16, 256.
- **GMP implementation:** gmp_init + bin2hex for 256 base
- **Bcmath implementation:** custom(bcadd + bcmul)
#### static BigInteger|false createSafe(ConvertibleToBi $value = 0, int $base = 10)
Creates a new BigInteger instance in the same way as constructor, but if there is an error, false will be returned instead of throwing an exception.
#### BigInteger add(ConvertibleToBi $x)
Adds numbers
- **GMP implementation:** gmp_add
- **Bcmath implementation:** bcadd
#### BigInteger sub(ConvertibleToBi $x)
Subtracts numbers
- **GMP implementation:** gmp_sub
- **Bcmath implementation:** bcsub
#### BigInteger mul(ConvertibleToBi $x)
Multiplies numbers
- **GMP implementation:** gmp_mul
- **Bcmath implementation:** bcmul
#### BigInteger div(ConvertibleToBi $x)
Divides numbers
- **GMP implementation:** gmp_div_q
- **Bcmath implementation:** bcdiv
#### BigInteger divR(ConvertibleToBi $x)
Returns a remainder of the division of numbers. The remainder has the sign of the divided number.
- **GMP implementation:** gmp_div_r
- **Bcmath implementation:** bcmod
#### array(BigInteger, BigInteger) divQR(ConvertibleToBi $x)
Divides numbers and returns quotient and remainder. Returns an array(), with the first element being quotient, and the second being remainder.
- **GMP implementation:** gmp_div_qr
- **Bcmath implementation:** div + divR
#### BigInteger mod(ConvertibleToBi $x)
The "division modulo" operation. The result is always non-negative, the sign of divider is ignored.
- **GMP implementation:** gmp_mod
- **Bcmath implementation:** custom (bcmod + bcadd)
#### BigInteger gcd(ConvertibleToBi $x)
Calculates greatest common divisor
- **GMP implementation:** gmp_gcd
- **Bcmath implementation:** custom (bccomp + bcdiv + bcsub + bcmul)
#### BigInteger|false modInverse(ConvertibleToBi $x)
Inverses by modulo, returns false if inversion does not exist.
- **GMP implementation:** gmp_invert
- **Bcmath implementation:** custom (gcd)
#### BigInteger pow(ConvertibleToBi $x)
The power function.
- **GMP implementation:** gmp_pow
- **Bcmath implementation:** bcpow
#### BigInteger powMod(ConvertibleToBi $x, ConvertibleToBi $n)
The modular power function.
- **GMP implementation:** gmp_powm
- **Bcmath implementation:** bcpowmod
#### BigInteger abs()
Returns absolute value.
- **GMP implementation:** gmp_abs
- **Bcmath implementation:** check first character
#### BigInteger neg()
Negates the number
- **GMP implementation:** gmp_neg
- **Bcmath implementation:** check first character
#### BigInteger binaryAnd(ConvertibleToBi $x)
Bitwise AND.
- **GMP implementation:** gmp_and
- **Bcmath implementation:** custom (toBytes + php string and)
#### BigInteger binaryOr(ConvertibleToBi $x)
Bitwise OR
- **GMP implementation:** gmp_or
- **Bcmath implementation:** custom (toBytes + php string or)
#### BigInteger binaryXor(ConvertibleToBi $x)
Bitwise XOR
- **GMP implementation:** gmp_xor
- **Bcmath implementation:** custom (toBytes + php string xor)
#### BigInteger setbit($index, $bitOn = true)
Sets bit at given index
- **GMP implementation:** gmp_setbit
- **Bcmath implementation:** custom (toBits)
#### bool testbit($index)
Tests if a bit at given index is set
- **GMP implementation:** gmp_testbit
- **Bcmath implementation:** custom (toBits)
#### int scan0($start)
Scans for 0, and returns index of first found bit
- **GMP implementation:** gmp_scan0
- **Bcmath implementation:** custom (toBits)
#### int scan1($start)
Scans for 1, and returns index of first found bit
- **GMP implementation:** gmp_scan1
- **Bcmath implementation:** custom (toBits)
#### int cmp(ConvertibleToBi $x)
Compares numbers, returns <0, 0, >0
- **GMP implementation:** gmp_cmp
- **Bcmath implementation:** bccomp
#### bool equals(ConvertibleToBi $x)
Checks if numbers are equal
- **GMP implementation:** gmp_cmp
- **Bcmath implementation:** bccomp
#### int sign()
Sign of number, returns -1, 0, 1
- **GMP implementation:** gmp_sign
- **Bcmath implementation:** check first character
#### int toNumber()
Converts to number (use only with small 32/64bit numbers)
- **GMP implementation:** gmp_intval
- **Bcmath implementation:** intval
#### string toDec()
Converts to decimal string
- **GMP implementation:** gmp_strval
- **Bcmath implementation:** just the value
#### string toHex()
Converts to hex string
- **GMP implementation:** gmp_strval
- **Bcmath implementation:** toBytes + bin2hex
#### string toBytes
Converts to binary string
- **GMP implementation:** gmp_strval + hex2bin
- **Bcmath implementation:** custom (bcmod + bcdiv + bccomp)
#### string toBits()
Converts to bits string (0 and 1 characters)
- **GMP implementation:** gmp_strval
- **Bcmath implementation:** toBytes + decbin
#### string toString(int $base = 10)
Converts to string using given base (supported bases 2-62, 256)
- **GMP implementation:** all above toX functions, and for non standard gmp_strval
- **Bcmath implementation:** all above toX functions, and for non standard bcmod + bcdiv + bccomp
+17
View File
@@ -0,0 +1,17 @@
{
"name": "simplito/bigint-wrapper-php",
"description": "Common interface for php_gmp and php_bcmath modules",
"license": "MIT",
"authors": [
{
"name": "Simplito Team",
"email": "s.smyczynski@simplito.com",
"homepage": "https://simplito.com"
}
],
"autoload": {
"psr-4": {
"BI\\": "lib/"
}
}
}
+635
View File
@@ -0,0 +1,635 @@
<?php
namespace BI;
if (!defined("S_MATH_BIGINTEGER_MODE")) {
if (extension_loaded("gmp")) {
define("S_MATH_BIGINTEGER_MODE", "gmp");
}
else if (extension_loaded("bcmath")) {
define("S_MATH_BIGINTEGER_MODE", "bcmath");
}
else {
if (!defined("S_MATH_BIGINTEGER_QUIET")) {
throw new \Exception("Cannot use BigInteger. Neither gmp nor bcmath module is loaded");
}
}
}
if (S_MATH_BIGINTEGER_MODE == "gmp") {
if (!extension_loaded("gmp")) {
throw new \Exception("Extension gmp not loaded");
}
class BigInteger {
public $value;
public function __construct($value = 0, $base = 10) {
$this->value = $base === true ? $value : BigInteger::getGmp($value, $base);
}
public static function createSafe($value = 0, $base = 10) {
try {
return new BigInteger($value, $base);
}
catch (\Exception $e) {
return false;
}
}
public static function isGmp($var) {
if (is_resource($var)) {
return get_resource_type($var) == "GMP integer";
}
if (class_exists("GMP") && $var instanceof \GMP) {
return true;
}
return false;
}
public static function getGmp($value = 0, $base = 10) {
if ($value instanceof BigInteger) {
return $value->value;
}
if (BigInteger::isGmp($value)) {
return $value;
}
$type = gettype($value);
if ($type == "integer") {
$gmp = gmp_init($value);
if ($gmp === false) {
throw new \Exception("Cannot initialize");
}
return $gmp;
}
if ($type == "string") {
if ($base != 2 && $base != 10 && $base != 16 && $base != 256) {
throw new \Exception("Unsupported BigInteger base");
}
if ($base == 256) {
$value = bin2hex($value);
$base = 16;
}
$level = error_reporting();
error_reporting(0);
$gmp = gmp_init($value, $base);
error_reporting($level);
if ($gmp === false) {
throw new \Exception("Cannot initialize");
}
return $gmp;
}
throw new \Exception("Unsupported value, only string and integer are allowed, receive " . $type . ($type == "object" ? ", class: " . get_class($value) : ""));
}
public function toDec() {
return gmp_strval($this->value, 10);
}
public function toHex() {
$hex = gmp_strval($this->value, 16);
return strlen($hex) % 2 == 1 ? "0". $hex : $hex;
}
public function toBytes() {
return hex2bin($this->toHex());
}
public function toBase($base) {
if ($base < 2 || $base > 62) {
throw new \Exception("Invalid base");
}
return gmp_strval($this->value, $base);
}
public function toBits() {
return gmp_strval($this->value, 2);
}
public function toString($base = 10) {
if ($base == 2) {
return $this->toBits();
}
if ($base == 10) {
return $this->toDec();
}
if ($base == 16) {
return $this->toHex();
}
if ($base == 256) {
return $this->toBytes();
}
return $this->toBase($base);
}
public function __toString() {
return $this->toString();
}
public function toNumber() {
return gmp_intval($this->value);
}
public function add($x) {
return new BigInteger(gmp_add($this->value, BigInteger::getGmp($x)), true);
}
public function sub($x) {
return new BigInteger(gmp_sub($this->value, BigInteger::getGmp($x)), true);
}
public function mul($x) {
return new BigInteger(gmp_mul($this->value, BigInteger::getGmp($x)), true);
}
public function div($x) {
return new BigInteger(gmp_div_q($this->value, BigInteger::getGmp($x)), true);
}
public function divR($x) {
return new BigInteger(gmp_div_r($this->value, BigInteger::getGmp($x)), true);
}
public function divQR($x) {
$res = gmp_div_qr($this->value, BigInteger::getGmp($x));
return array(new BigInteger($res[0], true), new BigInteger($res[1], true));
}
public function mod($x) {
return new BigInteger(gmp_mod($this->value, BigInteger::getGmp($x)), true);
}
public function gcd($x) {
return new BigInteger(gmp_gcd($this->value, BigInteger::getGmp($x)), true);
}
public function modInverse($x) {
$res = gmp_invert($this->value, BigInteger::getGmp($x));
return $res === false ? false : new BigInteger($res, true);
}
public function pow($x) {
return new BigInteger(gmp_pow($this->value, (new BigInteger($x))->toNumber()), true);
}
public function powMod($x, $n) {
return new BigInteger(gmp_powm($this->value, BigInteger::getGmp($x), BigInteger::getGmp($n)), true);
}
public function abs() {
return new BigInteger(gmp_abs($this->value), true);
}
public function neg() {
return new BigInteger(gmp_neg($this->value), true);
}
public function binaryAnd($x) {
return new BigInteger(gmp_and($this->value, BigInteger::getGmp($x)), true);
}
public function binaryOr($x) {
return new BigInteger(gmp_or($this->value, BigInteger::getGmp($x)), true);
}
public function binaryXor($x) {
return new BigInteger(gmp_xor($this->value, BigInteger::getGmp($x)), true);
}
public function setbit($index, $bitOn = true) {
$cpy = gmp_init(gmp_strval($this->value, 16), 16);
gmp_setbit($cpy, $index, $bitOn);
return new BigInteger($cpy, true);
}
public function testbit($index) {
return gmp_testbit($this->value, $index);
}
public function scan0($start) {
return gmp_scan0($this->value, $start);
}
public function scan1($start) {
return gmp_scan1($this->value, $start);
}
public function cmp($x) {
return gmp_cmp($this->value, BigInteger::getGmp($x));
}
public function equals($x) {
return $this->cmp($x) === 0;
}
public function sign() {
return gmp_sign($this->value);
}
}
}
else if (S_MATH_BIGINTEGER_MODE == "bcmath") {
if (!extension_loaded("bcmath")) {
throw new \Exception("Extension bcmath not loaded");
}
class BigInteger{
public static $chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv";
public $value;
public function __construct($value = 0, $base = 10) {
$this->value = $base === true ? $value : BigInteger::getBC($value, $base);
}
public static function createSafe($value = 0, $base = 10) {
try {
return new BigInteger($value, $base);
}
catch (\Exception $e) {
return false;
}
}
public static function checkBinary($str) {
$len = strlen($str);
for ($i = 0; $i < $len; $i++) {
$c = ord($str[$i]);
if (($i != 0 || $c != 45) && ($c < 48 || $c > 49)) {
return false;
}
}
return true;
}
public static function checkDecimal($str) {
$len = strlen($str);
for ($i = 0; $i < $len; $i++) {
$c = ord($str[$i]);
if (($i != 0 || $c != 45) && ($c < 48 || $c > 57)) {
return false;
}
}
return true;
}
public static function checkHex($str) {
$len = strlen($str);
for ($i = 0; $i < $len; $i++) {
$c = ord($str[$i]);
if (($i != 0 || $c != 45) && ($c < 48 || $c > 57) && ($c < 65 || $c > 70) && ($c < 97 || $c > 102)) {
return false;
}
}
return true;
}
public static function getBC($value = 0, $base = 10) {
if ($value instanceof BigInteger) {
return $value->value;
}
$type = gettype($value);
if ($type == "integer") {
return strval($value);
}
if ($type == "string") {
if ($base == 2) {
$value = str_replace(" ", "", $value);
if (!BigInteger::checkBinary($value)) {
throw new \Exception("Invalid characters");
}
$minus = $value[0] == "-";
if ($minus) {
$value = substr($value, 1);
}
$len = strlen($value);
$m = 1;
$res = "0";
for ($i = $len - 1; $i >= 0; $i -= 8) {
$h = $i - 7 < 0 ? substr($value, 0, $i + 1) : substr($value, $i - 7, 8);
$res = bcadd($res, bcmul(bindec($h), $m, 0), 0);
$m = bcmul($m, "256", 0);
}
return ($minus ? "-" : "") . $res;
}
if ($base == 10) {
$value = str_replace(" ", "", $value);
if (!BigInteger::checkDecimal($value)) {
throw new \Exception("Invalid characters");
}
return $value;
}
if ($base == 16) {
$value = str_replace(" ", "", $value);
if (!BigInteger::checkHex($value)) {
throw new \Exception("Invalid characters");
}
$minus = $value[0] == "-";
if ($minus) {
$value = substr($value, 1);
}
$len = strlen($value);
$m = 1;
$res = "0";
for ($i = $len - 1; $i >= 0; $i -= 2) {
$h = $i == 0 ? "0" . substr($value, 0, 1) : substr($value, $i - 1, 2);
$res = bcadd($res, bcmul(hexdec($h), $m, 0), 0);
$m = bcmul($m, "256", 0);
}
return ($minus ? "-" : "") . $res;
}
if ($base == 256) {
$len = strlen($value);
$m = 1;
$res = "0";
for ($i = $len - 1; $i >= 0; $i -= 6) {
$h = $i - 5 < 0 ? substr($value, 0, $i + 1) : substr($value, $i - 5, 6);
$res = bcadd($res, bcmul(base_convert(bin2hex($h), 16, 10), $m, 0), 0);
$m = bcmul($m, "281474976710656", 0);
}
return $res;
}
throw new \Exception("Unsupported BigInteger base");
}
throw new \Exception("Unsupported value, only string and integer are allowed, receive " . $type . ($type == "object" ? ", class: " . get_class($value) : ""));
}
public function toDec() {
return $this->value;
}
public function toHex() {
return bin2hex($this->toBytes());
}
public function toBytes() {
$value = "";
$current = $this->value;
if ($current[0] == "-") {
$current = substr($current, 1);
}
while (bccomp($current, "0", 0) > 0) {
$temp = bcmod($current, "281474976710656");
$value = hex2bin(str_pad(base_convert($temp, 10, 16), 12, "0", STR_PAD_LEFT)) . $value;
$current = bcdiv($current, "281474976710656", 0);
}
return ltrim($value, chr(0));
}
public function toBase($base) {
if ($base < 2 || $base > 62) {
throw new \Exception("Invalid base");
}
$value = '';
$current = $this->value;
$base = BigInteger::getBC($base);
if ($current[0] == '-') {
$current = substr($current, 1);
}
while (bccomp($current, '0', 0) > 0) {
$v = bcmod($current, $base);
$value = BigInteger::$chars[$v] . $value;
$current = bcdiv($current, $base, 0);
}
return $value;
}
public function toBits() {
$bytes = $this->toBytes();
$res = "";
$len = strlen($bytes);
for ($i = 0; $i < $len; $i++) {
$b = decbin(ord($bytes[$i]));
$res .= strlen($b) != 8 ? str_pad($b, 8, "0", STR_PAD_LEFT) : $b;
}
$res = ltrim($res, "0");
return strlen($res) == 0 ? "0" : $res;
}
public function toString($base = 10) {
if ($base == 2) {
return $this->toBits();
}
if ($base == 10) {
return $this->toDec();
}
if ($base == 16) {
return $this->toHex();
}
if ($base == 256) {
return $this->toBytes();
}
return $this->toBase($base);
}
public function __toString() {
return $this->toString();
}
public function toNumber() {
return intval($this->value);
}
public function add($x) {
return new BigInteger(bcadd($this->value, BigInteger::getBC($x), 0), true);
}
public function sub($x) {
return new BigInteger(bcsub($this->value, BigInteger::getBC($x), 0), true);
}
public function mul($x) {
return new BigInteger(bcmul($this->value, BigInteger::getBC($x), 0), true);
}
public function div($x) {
return new BigInteger(bcdiv($this->value, BigInteger::getBC($x), 0), true);
}
public function divR($x) {
return new BigInteger(bcmod($this->value, BigInteger::getBC($x)), true);
}
public function divQR($x) {
return array(
$this->div($x),
$this->divR($x)
);
}
public function mod($x) {
$xv = BigInteger::getBC($x);
$mod = bcmod($this->value, $xv);
if ($mod[0] == "-") {
$mod = bcadd($mod, $xv[0] == "-" ? substr($xv, 1) : $xv, 0);
}
return new BigInteger($mod, true);
}
public function extendedGcd($n) {
$u = $this->value;
$v = (new BigInteger($n))->abs()->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" => new BigInteger($u, true),
"x" => new BigInteger($a, true),
"y" => new BigInteger($b, true)
);
}
public function gcd($x) {
return $this->extendedGcd($x)["gcd"];
}
public function modInverse($n) {
$n = (new BigInteger($n))->abs();
if ($this->sign() < 0) {
$temp = $this->abs();
$temp = $temp->modInverse($n);
return $n->sub($temp);
}
extract($this->extendedGcd($n));
if (!$gcd->equals(1)) {
return false;
}
$x = $x->sign() < 0 ? $x->add($n) : $x;
return $this->sign() < 0 ? $n->sub($x) : $x;
}
public function pow($x) {
return new BigInteger(bcpow($this->value, BigInteger::getBC($x), 0), true);
}
public function powMod($x, $n) {
return new BigInteger(bcpowmod($this->value, BigInteger::getBC($x), BigInteger::getBC($n), 0), true);
}
public function abs() {
return new BigInteger($this->value[0] == "-" ? substr($this->value, 1) : $this->value, true);
}
public function neg() {
return new BigInteger($this->value[0] == "-" ? substr($this->value, 1) : "-" . $this->value, true);
}
public function binaryAnd($x) {
$left = $this->toBytes();
$right = (new BigInteger($x))->toBytes();
$length = max(strlen($left), strlen($right));
$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
return new BigInteger($left & $right, 256);
}
public function binaryOr($x) {
$left = $this->toBytes();
$right = (new BigInteger($x))->toBytes();
$length = max(strlen($left), strlen($right));
$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
return new BigInteger($left | $right, 256);
}
public function binaryXor($x) {
$left = $this->toBytes();
$right = (new BigInteger($x))->toBytes();
$length = max(strlen($left), strlen($right));
$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
return new BigInteger($left ^ $right, 256);
}
public function setbit($index, $bitOn = true) {
$bits = $this->toBits();
$bits[strlen($bits) - $index - 1] = $bitOn ? "1" : "0";
return new BigInteger($bits, 2);
}
public function testbit($index) {
$bytes = $this->toBytes();
$bytesIndex = intval($index / 8);
$len = strlen($bytes);
$b = $bytesIndex >= $len ? 0 : ord($bytes[$len - $bytesIndex - 1]);
$v = 1 << ($index % 8);
return ($b & $v) === $v;
}
public function scan0($start) {
$bits = $this->toBits();
$len = strlen($bits);
if ($start < 0 || $start >= $len) {
return -1;
}
$pos = strrpos($bits, "0", -1 - $start);
return $pos === false ? -1 : $len - $pos - 1;
}
public function scan1($start) {
$bits = $this->toBits();
$len = strlen($bits);
if ($start < 0 || $start >= $len) {
return -1;
}
$pos = strrpos($bits, "1", -1 - $start);
return $pos === false ? -1 : $len - $pos - 1;
}
public function cmp($x) {
return bccomp($this->value, BigInteger::getBC($x));
}
public function equals($x) {
return $this->value === BigInteger::getBC($x);
}
public function sign() {
return $this->value[0] === "-" ? -1 : ($this->value === "0" ? 0 : 1);
}
}
}
else {
if (!defined("S_MATH_BIGINTEGER_QUIET")) {
throw new \Exception("Unsupported S_MATH_BIGINTEGER_MODE " . S_MATH_BIGINTEGER_MODE);
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
define('S_MATH_BIGINTEGER_MODE', "bcmath");
require(__DIR__ . "/../lib/BigInteger.php");
use BI\BigInteger;
$a = new BigInteger("4547395333333333333333333333333333333333333343587493875493579375498759837593574935739857");
$b = new BigInteger("-4547395333333333333333333333333333333333333343587493875493579375498759837593574935739857");
$c = new BigInteger("0");
$hex = "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3";
$bytes = hex2bin($hex);
function test($v, $b) {
$start = microtime(true);
$count = 10000;
for ($i = 0; $i < $count; $i++) {
$v->binaryAnd($b);
//$v->toBytes();
//BigInteger::getBC($v, 256);
}
$end = microtime(true);
error_log($end - $start);
}
test($a, $a);
test($b, $b);
//test($bytes, $b);
+119
View File
@@ -0,0 +1,119 @@
<?php
use BI\BigInteger;
function test($a, $b, $message = "") {
error_log(($a === $b ? "PASS" : "FAIL get: " . $a . ", expected: " . $b) . " " . $message);
}
function testB($a, $b, $message = "") {
error_log(($a->toString() === $b ? "PASS" : "FAIL get: " . $a . ", expected: " . $b) . " " . $message);
}
function testSerialization($b, $msg = "") {
test($b->toBits(), "1010000", $msg . " toBits");
test($b->toBytes(), hex2bin("50"), $msg . " toBytes");
test($b->toHex(), "50", $msg . " toHex");
test($b->toDec(), "80", $msg . " toDec");
test($b->toNumber(), 80, $msg . " toNumber");
test($b->toBase(58), "1M", $msg . " to58");
}
function testCreate() {
error_log("=============\nTest serialization\n=============");
testSerialization(new BigInteger("1010000", 2), "bits");
testSerialization(new BigInteger(hex2bin("50"), 256), "bytes");
testSerialization(new BigInteger("50", 16), "hex");
testSerialization(new BigInteger("80", 10), "dec");
testSerialization(new BigInteger("80"), "dec2");
testSerialization(new BigInteger(80), "number");
}
function testCreateSafeSingle($value, $base, $msg) {
try {
$z = new BigInteger($value, $base);
error_log("FAIL exception during create " . $msg);
}
catch (\Exception $e) {
error_log("PASS exception during create " . $msg);
}
test(BigInteger::createSafe($value, $base), false, "createSafe " . $msg);
}
function testCreateSafe() {
error_log("=============\nTest create safe\n=============");
testCreateSafeSingle("zz", 2, "bin");
testCreateSafeSingle("zz", 10, "dec");
testCreateSafeSingle("zz", 16, "hex");
}
function testSpaces() {
error_log("=============\nTest spaces\n=============");
test((new BigInteger("11 0 1", 2))->toBits(), "1101", "bin");
test((new BigInteger("6 2 0 6", 10))->toDec(), "6206", "dec");
test((new BigInteger("f3 5 12 ac 0", 16))->toHex(), "f3512ac0", "hex");
}
function testOp() {
error_log("=============\nTest op\n=============");
testB((new BigInteger(20))->add(34), "54", "add");
testB((new BigInteger(20))->sub(14), "6", "sub");
testB((new BigInteger(20))->mul(12), "240", "mul");
testB((new BigInteger(20))->div(4), "5", "div");
testB((new BigInteger(20))->divR(7), "6", "divR");
$qr = (new BigInteger(20))->divQR(6);
testB($qr[0], "3", "divQR[0]");
testB($qr[1], "2", "divQR[1]");
testB((new BigInteger(20))->mod(3), "2", "mod");
testB((new BigInteger(54))->gcd(81), "27", "gcd");
testB((new BigInteger(3))->modInverse(10), "7", "modInverse");
testB((new BigInteger(3))->pow(4), "81", "pow");
testB((new BigInteger(3))->powMod(4, 10), "1", "powMod");
testB((new BigInteger(20))->abs(), "20", "abs");
testB((new BigInteger(20))->neg(), "-20", "neg");
testB((new BigInteger(20))->binaryAnd(18), "16", "binaryAnd");
testB((new BigInteger(20))->binaryOr(18), "22", "binaryOr");
testB((new BigInteger(20))->binaryXor(18), "6", "binaryXor");
testB((new BigInteger(20))->setbit(3), "28", "setbit");
test((new BigInteger(20))->testbit(4), true, "testbit true");
test((new BigInteger(20))->testbit(3), false, "testbit false");
test((new BigInteger(5))->testbit(0), true, "testbit 0 true");
test((new BigInteger(6))->testbit(0), false, "testbit 0 false");
test((new BigInteger(6))->testbit(1), true, "testbit 1 true");
test((new BigInteger(5))->testbit(1), false, "testbit 1 false");
test((new BigInteger(132))->testbit(7), true, "testbit 7 true");
test((new BigInteger(81))->testbit(7), false, "testbit 7 false");
test((new BigInteger(258))->testbit(8), true, "testbit 8 true");
test((new BigInteger(253))->testbit(8), false, "testbit 8 false");
test((new BigInteger(20))->scan0(2), 3, "scan0");
test((new BigInteger(20))->scan1(3), 4, "scan1");
test((new BigInteger(20))->cmp(22), -1, "cmp -1");
test((new BigInteger(20))->cmp(20), 0, "cmp 0");
test((new BigInteger(20))->cmp(18), 1, "cmp 1");
test((new BigInteger(20))->equals(20), true, "equals true");
test((new BigInteger(20))->equals(21), false, "equals false");
test((new BigInteger(-20))->sign(), -1, "sign -1");
test((new BigInteger(0))->sign(), 0, "sign 0");
test((new BigInteger(20))->sign(), 1, "sign 1");
testB(new BigInteger("-20"), "-20", "minus");
testB(new BigInteger("-14", 16), "-20", "minus");
testB(new BigInteger("-10100", 2), "-20", "minus");
}
function testBig() {
error_log("=============\nTest big\n=============");
$bits = "1001010111010010100001000101110110100001000101101000110101010101001";
$hex = "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3";
$dec = "436529472098746319073192837123683467019263172846";
$bytes = hex2bin($hex);
test((new BigInteger($bits, 2))->toBits(), $bits, "init big from binary");
test((new BigInteger($dec, 10))->toDec(), $dec, "init big from dec");
test((new BigInteger($hex, 16))->toHex(), $hex, "init big from hex");
test((new BigInteger($bytes, 256))->toBytes(), $bytes, "init big from buffer");
}
testCreate();
testCreateSafe();
testSpaces();
testOp();
testBig();
+6
View File
@@ -0,0 +1,6 @@
<?php
define('S_MATH_BIGINTEGER_MODE', "bcmath");
require(__DIR__ . "/../lib/BigInteger.php");
require(__DIR__ . "/test.php");
+6
View File
@@ -0,0 +1,6 @@
<?php
define('S_MATH_BIGINTEGER_MODE', "gmp");
require(__DIR__ . "/../lib/BigInteger.php");
require(__DIR__ . "/test.php");