Viel neues
This commit is contained in:
773
qa-tool/htdocs/oidc/phpseclib/Math/BigInteger.php
Normal file
773
qa-tool/htdocs/oidc/phpseclib/Math/BigInteger.php
Normal file
@@ -0,0 +1,773 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Pure-PHP arbitrary precision integer arithmetic library.
|
||||
*
|
||||
* Supports base-2, base-10, base-16, and base-256 numbers. Uses the GMP or BCMath extensions, if available,
|
||||
* and an internal implementation, otherwise.
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* Here's an example of how to use this library:
|
||||
* <code>
|
||||
* <?php
|
||||
* $a = new \phpseclib3\Math\BigInteger(2);
|
||||
* $b = new \phpseclib3\Math\BigInteger(3);
|
||||
*
|
||||
* $c = $a->add($b);
|
||||
*
|
||||
* echo $c->toString(); // outputs 5
|
||||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math;
|
||||
|
||||
use phpseclib3\Exception\BadConfigurationException;
|
||||
use phpseclib3\Exception\InvalidArgumentException;
|
||||
use phpseclib3\Exception\UnexpectedValueException;
|
||||
use phpseclib3\Math\BigInteger\Engines\Engine;
|
||||
|
||||
/**
|
||||
* Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
|
||||
* numbers.
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class BigInteger implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* Main Engine
|
||||
*
|
||||
* @var class-string<Engine>
|
||||
*/
|
||||
private static $mainEngine;
|
||||
|
||||
/**
|
||||
* Selected Engines
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
private static $engines;
|
||||
|
||||
/**
|
||||
* The actual BigInteger object
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* Mode independent value used for serialization.
|
||||
*
|
||||
* @see self::__sleep()
|
||||
* @see self::__wakeup()
|
||||
* @var string
|
||||
*/
|
||||
private $hex;
|
||||
|
||||
/**
|
||||
* Precision (used only for serialization)
|
||||
*
|
||||
* @see self::__sleep()
|
||||
* @see self::__wakeup()
|
||||
* @var int
|
||||
*/
|
||||
private $precision;
|
||||
|
||||
/**
|
||||
* Sets engine type.
|
||||
*
|
||||
* Throws an exception if the type is invalid
|
||||
*
|
||||
* @param list<string> $modexps optional
|
||||
*/
|
||||
public static function setEngine(string $main, array $modexps = ['DefaultEngine']): void
|
||||
{
|
||||
self::$engines = [];
|
||||
|
||||
$fqmain = 'phpseclib3\\Math\\BigInteger\\Engines\\' . $main;
|
||||
if (!class_exists($fqmain) || !method_exists($fqmain, 'isValidEngine')) {
|
||||
throw new InvalidArgumentException("$main is not a valid engine");
|
||||
}
|
||||
if (!$fqmain::isValidEngine()) {
|
||||
throw new BadConfigurationException("$main is not setup correctly on this system");
|
||||
}
|
||||
/** @var class-string<Engine> $fqmain */
|
||||
self::$mainEngine = $fqmain;
|
||||
|
||||
$found = false;
|
||||
foreach ($modexps as $modexp) {
|
||||
try {
|
||||
$fqmain::setModExpEngine($modexp);
|
||||
$found = true;
|
||||
break;
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!$found) {
|
||||
throw new BadConfigurationException("No valid modular exponentiation engine found for $main");
|
||||
}
|
||||
|
||||
self::$engines = [$main, $modexp];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the engine type
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getEngine(): array
|
||||
{
|
||||
self::initialize_static_variables();
|
||||
|
||||
return self::$engines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize static variables
|
||||
*/
|
||||
private static function initialize_static_variables(): void
|
||||
{
|
||||
if (!isset(self::$mainEngine)) {
|
||||
$engines = [
|
||||
['GMP', ['DefaultEngine']],
|
||||
['PHP64', ['OpenSSL']],
|
||||
['BCMath', ['OpenSSL']],
|
||||
['PHP32', ['OpenSSL']],
|
||||
['PHP64', ['DefaultEngine']],
|
||||
['PHP32', ['DefaultEngine']],
|
||||
];
|
||||
|
||||
foreach ($engines as $engine) {
|
||||
try {
|
||||
self::setEngine($engine[0], $engine[1]);
|
||||
return;
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
throw new UnexpectedValueException('No valid BigInteger found. This is only possible when JIT is enabled on Windows and neither the GMP or BCMath extensions are available so either disable JIT or install GMP / BCMath');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.
|
||||
*
|
||||
* If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
|
||||
* two's compliment. The sole exception to this is -10, which is treated the same as 10 is.
|
||||
*
|
||||
* @param string|int|Engine $x Base-10 number or base-$base number if $base set.
|
||||
*/
|
||||
public function __construct($x = 0, int $base = 10)
|
||||
{
|
||||
self::initialize_static_variables();
|
||||
|
||||
if ($x instanceof self::$mainEngine) {
|
||||
$this->value = clone $x;
|
||||
} elseif ($x instanceof Engine) {
|
||||
$this->value = new static("$x");
|
||||
$this->value->setPrecision($x->getPrecision());
|
||||
} else {
|
||||
$this->value = new self::$mainEngine($x, $base);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a BigInteger to a base-10 number.
|
||||
*/
|
||||
public function toString(): string
|
||||
{
|
||||
return $this->value->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* __toString() magic method
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string)$this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* __debugInfo() magic method
|
||||
*
|
||||
* Will be called, automatically, when print_r() or var_dump() are called
|
||||
*/
|
||||
public function __debugInfo()
|
||||
{
|
||||
return $this->value->__debugInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a BigInteger to a byte string (eg. base-256).
|
||||
*/
|
||||
public function toBytes(bool $twos_compliment = false): string
|
||||
{
|
||||
return $this->value->toBytes($twos_compliment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a BigInteger to a hex string (eg. base-16).
|
||||
*/
|
||||
public function toHex(bool $twos_compliment = false): string
|
||||
{
|
||||
return $this->value->toHex($twos_compliment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a BigInteger to a bit string (eg. base-2).
|
||||
*
|
||||
* Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
|
||||
* saved as two's compliment.
|
||||
*/
|
||||
public function toBits(bool $twos_compliment = false): string
|
||||
{
|
||||
return $this->value->toBits($twos_compliment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two BigIntegers.
|
||||
*/
|
||||
public function add(BigInteger $y): BigInteger
|
||||
{
|
||||
return new static($this->value->add($y->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts two BigIntegers.
|
||||
*/
|
||||
public function subtract(BigInteger $y): BigInteger
|
||||
{
|
||||
return new static($this->value->subtract($y->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two BigIntegers
|
||||
*/
|
||||
public function multiply(BigInteger $x): BigInteger
|
||||
{
|
||||
return new static($this->value->multiply($x->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (basically, the "common residue" is the first positive modulo).
|
||||
*
|
||||
* Here's an example:
|
||||
* <code>
|
||||
* <?php
|
||||
* $a = new \phpseclib3\Math\BigInteger('10');
|
||||
* $b = new \phpseclib3\Math\BigInteger('20');
|
||||
*
|
||||
* list($quotient, $remainder) = $a->divide($b);
|
||||
*
|
||||
* echo $quotient->toString(); // outputs 0
|
||||
* echo "\r\n";
|
||||
* echo $remainder->toString(); // outputs 10
|
||||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* @return BigInteger[]
|
||||
*/
|
||||
public function divide(BigInteger $y): array
|
||||
{
|
||||
[$q, $r] = $this->value->divide($y->value);
|
||||
return [
|
||||
new static($q),
|
||||
new static($r),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates modular inverses.
|
||||
*
|
||||
* Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
|
||||
*/
|
||||
public function modInverse(BigInteger $n): BigInteger
|
||||
{
|
||||
return new static($this->value->modInverse($n->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates modular inverses.
|
||||
*
|
||||
* Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
|
||||
*
|
||||
* @return BigInteger[]
|
||||
*/
|
||||
public function extendedGCD(BigInteger $n): array
|
||||
{
|
||||
extract($this->value->extendedGCD($n->value));
|
||||
/**
|
||||
* @var BigInteger $gcd
|
||||
* @var BigInteger $x
|
||||
* @var BigInteger $y
|
||||
*/
|
||||
return [
|
||||
'gcd' => new static($gcd),
|
||||
'x' => new static($x),
|
||||
'y' => new static($y),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the greatest common divisor
|
||||
*
|
||||
* Say you have 693 and 609. The GCD is 21.
|
||||
*/
|
||||
public function gcd(BigInteger $n): BigInteger
|
||||
{
|
||||
return new static($this->value->gcd($n->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute value.
|
||||
*/
|
||||
public function abs(): BigInteger
|
||||
{
|
||||
return new static($this->value->abs());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Precision
|
||||
*
|
||||
* Some bitwise operations give different results depending on the precision being used. Examples include left
|
||||
* shift, not, and rotates.
|
||||
*/
|
||||
public function setPrecision(int $bits): void
|
||||
{
|
||||
$this->value->setPrecision($bits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Precision
|
||||
*
|
||||
* Returns the precision if it exists, false if it doesn't
|
||||
*
|
||||
* @return int|bool
|
||||
*/
|
||||
public function getPrecision()
|
||||
{
|
||||
return $this->value->getPrecision();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize
|
||||
*
|
||||
* Will be called, automatically, when serialize() is called on a BigInteger object.
|
||||
*
|
||||
* __sleep() / __wakeup() have been around since PHP 4.0
|
||||
*
|
||||
* \Serializable was introduced in PHP 5.1 and deprecated in PHP 8.1:
|
||||
* https://wiki.php.net/rfc/phase_out_serializable
|
||||
*
|
||||
* __serialize() / __unserialize() were introduced in PHP 7.4:
|
||||
* https://wiki.php.net/rfc/custom_object_serialization
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function __sleep()
|
||||
{
|
||||
$this->hex = $this->toHex(true);
|
||||
$vars = ['hex'];
|
||||
if ($this->getPrecision() > 0) {
|
||||
$vars[] = 'precision';
|
||||
}
|
||||
return $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize
|
||||
*
|
||||
* Will be called, automatically, when unserialize() is called on a BigInteger object.
|
||||
*/
|
||||
public function __wakeup(): void
|
||||
{
|
||||
$temp = new static($this->hex, -16);
|
||||
$this->value = $temp->value;
|
||||
if ($this->precision > 0) {
|
||||
// recalculate $this->bitmask
|
||||
$this->setPrecision($this->precision);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON Serialize
|
||||
*
|
||||
* Will be called, automatically, when json_encode() is called on a BigInteger object.
|
||||
*
|
||||
* @return array{hex: string, precision?: int]
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$result = ['hex' => $this->toHex(true)];
|
||||
if ($this->precision > 0) {
|
||||
$result['precision'] = $this->getPrecision();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*/
|
||||
public function powMod(BigInteger $e, BigInteger $n): BigInteger
|
||||
{
|
||||
return new static($this->value->powMod($e->value, $n->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*/
|
||||
public function modPow(BigInteger $e, BigInteger $n): BigInteger
|
||||
{
|
||||
return new static($this->value->modPow($e->value, $n->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two numbers.
|
||||
*
|
||||
* Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this
|
||||
* is demonstrated thusly:
|
||||
*
|
||||
* $x > $y: $x->compare($y) > 0
|
||||
* $x < $y: $x->compare($y) < 0
|
||||
* $x == $y: $x->compare($y) == 0
|
||||
*
|
||||
* Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
|
||||
*
|
||||
* {@internal Could return $this->subtract($x), but that's not as fast as what we do do.}
|
||||
*
|
||||
* @return int in case < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
|
||||
* @see self::equals()
|
||||
*/
|
||||
public function compare(BigInteger $y): int
|
||||
{
|
||||
return $this->value->compare($y->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the equality of two numbers.
|
||||
*
|
||||
* If you need to see if one number is greater than or less than another number, use BigInteger::compare()
|
||||
*/
|
||||
public function equals(BigInteger $x): bool
|
||||
{
|
||||
return $this->value->equals($x->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Not
|
||||
*/
|
||||
public function bitwise_not(): BigInteger
|
||||
{
|
||||
return new static($this->value->bitwise_not());
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical And
|
||||
*/
|
||||
public function bitwise_and(BigInteger $x): BigInteger
|
||||
{
|
||||
return new static($this->value->bitwise_and($x->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Or
|
||||
*/
|
||||
public function bitwise_or(BigInteger $x): BigInteger
|
||||
{
|
||||
return new static($this->value->bitwise_or($x->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Exclusive Or
|
||||
*/
|
||||
public function bitwise_xor(BigInteger $x): BigInteger
|
||||
{
|
||||
return new static($this->value->bitwise_xor($x->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Right Shift
|
||||
*
|
||||
* Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
|
||||
*/
|
||||
public function bitwise_rightShift(int $shift): BigInteger
|
||||
{
|
||||
return new static($this->value->bitwise_rightShift($shift));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Left Shift
|
||||
*
|
||||
* Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
|
||||
*/
|
||||
public function bitwise_leftShift(int $shift): BigInteger
|
||||
{
|
||||
return new static($this->value->bitwise_leftShift($shift));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Left Rotate
|
||||
*
|
||||
* Instead of the top x bits being dropped they're appended to the shifted bit string.
|
||||
*/
|
||||
public function bitwise_leftRotate(int $shift): BigInteger
|
||||
{
|
||||
return new static($this->value->bitwise_leftRotate($shift));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Right Rotate
|
||||
*
|
||||
* Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
|
||||
*/
|
||||
public function bitwise_rightRotate(int $shift): BigInteger
|
||||
{
|
||||
return new static($this->value->bitwise_rightRotate($shift));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the smallest and largest n-bit number
|
||||
*
|
||||
* @return BigInteger[]
|
||||
*/
|
||||
public static function minMaxBits(int $bits): array
|
||||
{
|
||||
self::initialize_static_variables();
|
||||
|
||||
$class = self::$mainEngine;
|
||||
extract($class::minMaxBits($bits));
|
||||
/** @var BigInteger $min
|
||||
* @var BigInteger $max
|
||||
*/
|
||||
return [
|
||||
'min' => new static($min),
|
||||
'max' => new static($max),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of a BigInteger in bits
|
||||
*/
|
||||
public function getLength(): int
|
||||
{
|
||||
return $this->value->getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of a BigInteger in bytes
|
||||
*/
|
||||
public function getLengthInBytes(): int
|
||||
{
|
||||
return $this->value->getLengthInBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random number of a certain size
|
||||
*
|
||||
* Bit length is equal to $size
|
||||
*/
|
||||
public static function random(int $size): BigInteger
|
||||
{
|
||||
self::initialize_static_variables();
|
||||
|
||||
$class = self::$mainEngine;
|
||||
return new static($class::random($size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random prime number of a certain size
|
||||
*
|
||||
* Bit length is equal to $size
|
||||
*/
|
||||
public static function randomPrime(int $size): BigInteger
|
||||
{
|
||||
self::initialize_static_variables();
|
||||
|
||||
$class = self::$mainEngine;
|
||||
return new static($class::randomPrime($size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random prime number between a range
|
||||
*
|
||||
* If there's not a prime within the given range, false will be returned.
|
||||
*
|
||||
* @return false|BigInteger
|
||||
*/
|
||||
public static function randomRangePrime(BigInteger $min, BigInteger $max)
|
||||
{
|
||||
$class = self::$mainEngine;
|
||||
return new static($class::randomRangePrime($min->value, $max->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random number between a range
|
||||
*
|
||||
* Returns a random number between $min and $max where $min and $max
|
||||
* can be defined using one of the two methods:
|
||||
*
|
||||
* BigInteger::randomRange($min, $max)
|
||||
* BigInteger::randomRange($max, $min)
|
||||
*/
|
||||
public static function randomRange(BigInteger $min, BigInteger $max): BigInteger
|
||||
{
|
||||
$class = self::$mainEngine;
|
||||
return new static($class::randomRange($min->value, $max->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a numer to see if it's prime
|
||||
*
|
||||
* Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the
|
||||
* $t parameter is distributability. BigInteger::randomPrime() can be distributed across multiple pageloads
|
||||
* on a website instead of just one.
|
||||
*
|
||||
* @param int|bool $t
|
||||
*/
|
||||
public function isPrime($t = false): bool
|
||||
{
|
||||
return $this->value->isPrime($t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the nth root of a biginteger.
|
||||
*
|
||||
* Returns the nth root of a positive biginteger, where n defaults to 2
|
||||
*
|
||||
* @param int $n optional
|
||||
*/
|
||||
public function root(int $n = 2): BigInteger
|
||||
{
|
||||
return new static($this->value->root($n));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs exponentiation.
|
||||
*/
|
||||
public function pow(BigInteger $n): BigInteger
|
||||
{
|
||||
return new static($this->value->pow($n->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum BigInteger between an arbitrary number of BigIntegers.
|
||||
*/
|
||||
public static function min(BigInteger ...$nums): BigInteger
|
||||
{
|
||||
$class = self::$mainEngine;
|
||||
$nums = array_map(fn ($num) => $num->value, $nums);
|
||||
return new static($class::min(...$nums));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum BigInteger between an arbitrary number of BigIntegers.
|
||||
*/
|
||||
public static function max(BigInteger ...$nums): BigInteger
|
||||
{
|
||||
$class = self::$mainEngine;
|
||||
$nums = array_map(fn ($num) => $num->value, $nums);
|
||||
return new static($class::max(...$nums));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests BigInteger to see if it is between two integers, inclusive
|
||||
*/
|
||||
public function between(BigInteger $min, BigInteger $max): bool
|
||||
{
|
||||
return $this->value->between($min->value, $max->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
$this->value = clone $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Odd?
|
||||
*/
|
||||
public function isOdd(): bool
|
||||
{
|
||||
return $this->value->isOdd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a bit is set
|
||||
*/
|
||||
public function testBit(int $x): bool
|
||||
{
|
||||
return $this->value->testBit($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Negative?
|
||||
*/
|
||||
public function isNegative(): bool
|
||||
{
|
||||
return $this->value->isNegative();
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate
|
||||
*
|
||||
* Given $k, returns -$k
|
||||
*/
|
||||
public function negate(): BigInteger
|
||||
{
|
||||
return new static($this->value->negate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan for 1 and right shift by that amount
|
||||
*
|
||||
* ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
|
||||
*/
|
||||
public static function scan1divide(BigInteger $r): int
|
||||
{
|
||||
$class = self::$mainEngine;
|
||||
return $class::scan1divide($r->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Recurring Modulo Function
|
||||
*
|
||||
* Sometimes it may be desirable to do repeated modulos with the same number outside of
|
||||
* modular exponentiation
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
public function createRecurringModuloFunction()
|
||||
{
|
||||
$func = $this->value->createRecurringModuloFunction();
|
||||
return fn (BigInteger $x) => new static($func($x->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Bitwise Split
|
||||
*
|
||||
* Splits BigInteger's into chunks of $split bits
|
||||
*
|
||||
* @return BigInteger[]
|
||||
*/
|
||||
public function bitwise_split(int $split): array
|
||||
{
|
||||
return array_map(fn ($val) => new static($val), $this->value->bitwise_split($split));
|
||||
}
|
||||
}
|
||||
607
qa-tool/htdocs/oidc/phpseclib/Math/BigInteger/Engines/BCMath.php
Normal file
607
qa-tool/htdocs/oidc/phpseclib/Math/BigInteger/Engines/BCMath.php
Normal file
@@ -0,0 +1,607 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* BCMath BigInteger Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines;
|
||||
|
||||
use phpseclib3\Common\Functions\Strings;
|
||||
use phpseclib3\Exception\BadConfigurationException;
|
||||
|
||||
/**
|
||||
* BCMath Engine.
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class BCMath extends Engine
|
||||
{
|
||||
/**
|
||||
* Can Bitwise operations be done fast?
|
||||
*
|
||||
* @see parent::bitwise_leftRotate()
|
||||
* @see parent::bitwise_rightRotate()
|
||||
*/
|
||||
public const FAST_BITWISE = false;
|
||||
|
||||
/**
|
||||
* Engine Directory
|
||||
*
|
||||
* @see parent::setModExpEngine
|
||||
*/
|
||||
public const ENGINE_DIR = 'BCMath';
|
||||
|
||||
/**
|
||||
* Test for engine validity
|
||||
*
|
||||
* @see parent::__construct()
|
||||
*/
|
||||
public static function isValidEngine(): bool
|
||||
{
|
||||
return extension_loaded('bcmath');
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param mixed $x integer Base-10 number or base-$base number if $base set.
|
||||
* @see parent::__construct()
|
||||
*/
|
||||
public function __construct($x = 0, int $base = 10)
|
||||
{
|
||||
if (!isset(static::$isValidEngine[static::class])) {
|
||||
static::$isValidEngine[static::class] = self::isValidEngine();
|
||||
}
|
||||
if (!static::$isValidEngine[static::class]) {
|
||||
throw new BadConfigurationException('BCMath is not setup correctly on this system');
|
||||
}
|
||||
|
||||
$this->value = '0';
|
||||
|
||||
parent::__construct($x, $base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a BCMath BigInteger Engine instance
|
||||
*
|
||||
* @see parent::__construct()
|
||||
*/
|
||||
protected function initialize(int $base): void
|
||||
{
|
||||
switch (abs($base)) {
|
||||
case 256:
|
||||
// round $len to the nearest 4
|
||||
$len = (strlen($this->value) + 3) & ~3;
|
||||
|
||||
$x = str_pad($this->value, $len, chr(0), STR_PAD_LEFT);
|
||||
|
||||
$this->value = '0';
|
||||
for ($i = 0; $i < $len; $i += 4) {
|
||||
$this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
|
||||
$this->value = bcadd(
|
||||
$this->value,
|
||||
(string) (0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3]))),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->is_negative) {
|
||||
$this->value = '-' . $this->value;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
$x = (strlen($this->value) & 1) ? '0' . $this->value : $this->value;
|
||||
$temp = new self(Strings::hex2bin($x), 256);
|
||||
$this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
|
||||
$this->is_negative = false;
|
||||
break;
|
||||
case 10:
|
||||
// explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
|
||||
// results then doing it on '-1' does (modInverse does $x[0])
|
||||
$this->value = $this->value === '-' ? '0' : (string)$this->value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a BigInteger to a base-10 number.
|
||||
*/
|
||||
public function toString(): string
|
||||
{
|
||||
if ($this->value === '0') {
|
||||
return '0';
|
||||
}
|
||||
|
||||
return ltrim($this->value, '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a BigInteger to a byte string (eg. base-256).
|
||||
*/
|
||||
public function toBytes(bool $twos_compliment = false): string
|
||||
{
|
||||
if ($twos_compliment) {
|
||||
return $this->toBytesHelper();
|
||||
}
|
||||
|
||||
$value = '';
|
||||
$current = $this->value;
|
||||
|
||||
if ($current[0] == '-') {
|
||||
$current = substr($current, 1);
|
||||
}
|
||||
|
||||
while (bccomp($current, '0', 0) > 0) {
|
||||
$temp = bcmod($current, '16777216');
|
||||
$value = chr($temp >> 16) . chr($temp >> 8) . chr((int) $temp) . $value;
|
||||
$current = bcdiv($current, '16777216', 0);
|
||||
}
|
||||
|
||||
return $this->precision > 0 ?
|
||||
substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
|
||||
ltrim($value, chr(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two BigIntegers.
|
||||
*/
|
||||
public function add(BCMath $y): BCMath
|
||||
{
|
||||
$temp = new self();
|
||||
$temp->value = bcadd($this->value, $y->value);
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts two BigIntegers.
|
||||
*/
|
||||
public function subtract(BCMath $y): BCMath
|
||||
{
|
||||
$temp = new self();
|
||||
$temp->value = bcsub($this->value, $y->value);
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two BigIntegers.
|
||||
*/
|
||||
public function multiply(BCMath $x): BCMath
|
||||
{
|
||||
$temp = new self();
|
||||
$temp->value = bcmul($this->value, $x->value);
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (basically, the "common residue" is the first positive modulo).
|
||||
*
|
||||
* @return array{static, static}
|
||||
*/
|
||||
public function divide(BCMath $y): array
|
||||
{
|
||||
$quotient = new self();
|
||||
$remainder = new self();
|
||||
|
||||
$quotient->value = bcdiv($this->value, $y->value, 0);
|
||||
$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, 0);
|
||||
}
|
||||
|
||||
return [$this->normalize($quotient), $this->normalize($remainder)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates modular inverses.
|
||||
*
|
||||
* Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
|
||||
*
|
||||
* @return false|BCMath
|
||||
*/
|
||||
public function modInverse(BCMath $n)
|
||||
{
|
||||
return $this->modInverseHelper($n);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 dependent 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.
|
||||
*
|
||||
* @return array{gcd: static, x: static, y: static}
|
||||
*/
|
||||
public function extendedGCD(BCMath $n): array
|
||||
{
|
||||
// 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 [
|
||||
'gcd' => $this->normalize(new static($u)),
|
||||
'x' => $this->normalize(new static($a)),
|
||||
'y' => $this->normalize(new static($b)),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the greatest common divisor
|
||||
*
|
||||
* Say you have 693 and 609. The GCD is 21.
|
||||
*/
|
||||
public function gcd(BCMath $n): BCMath
|
||||
{
|
||||
extract($this->extendedGCD($n));
|
||||
/** @var BCMath $gcd */
|
||||
return $gcd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute value.
|
||||
*/
|
||||
public function abs(): BCMath
|
||||
{
|
||||
$temp = new static();
|
||||
$temp->value = strlen($this->value) && $this->value[0] == '-' ?
|
||||
substr($this->value, 1) :
|
||||
$this->value;
|
||||
|
||||
return $temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical And
|
||||
*/
|
||||
public function bitwise_and(BCMath $x): BCMath
|
||||
{
|
||||
return $this->bitwiseAndHelper($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Or
|
||||
*/
|
||||
public function bitwise_or(BCMath $x): BCMath
|
||||
{
|
||||
return $this->bitwiseOrHelper($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Exclusive Or
|
||||
*/
|
||||
public function bitwise_xor(BCMath $x): BCMath
|
||||
{
|
||||
return $this->bitwiseXorHelper($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Right Shift
|
||||
*
|
||||
* Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
|
||||
*/
|
||||
public function bitwise_rightShift(int $shift): BCMath
|
||||
{
|
||||
$temp = new static();
|
||||
$temp->value = bcdiv($this->value, bcpow('2', (string)$shift, 0), 0);
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Left Shift
|
||||
*
|
||||
* Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
|
||||
*/
|
||||
public function bitwise_leftShift(int $shift): BCMath
|
||||
{
|
||||
$temp = new static();
|
||||
$temp->value = bcmul($this->value, bcpow('2', (string) $shift, 0), 0);
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two numbers.
|
||||
*
|
||||
* Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this
|
||||
* is demonstrated thusly:
|
||||
*
|
||||
* $x > $y: $x->compare($y) > 0
|
||||
* $x < $y: $x->compare($y) < 0
|
||||
* $x == $y: $x->compare($y) == 0
|
||||
*
|
||||
* Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
|
||||
*
|
||||
* {@internal Could return $this->subtract($x), but that's not as fast as what we do do.}
|
||||
*
|
||||
* @return int in case < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
|
||||
* @see self::equals()
|
||||
*/
|
||||
public function compare(BCMath $y): int
|
||||
{
|
||||
return bccomp($this->value, $y->value, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the equality of two numbers.
|
||||
*
|
||||
* If you need to see if one number is greater than or less than another number, use BigInteger::compare()
|
||||
*/
|
||||
public function equals(BCMath $x): bool
|
||||
{
|
||||
return $this->value == $x->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*/
|
||||
public function modPow(BCMath $e, BCMath $n): BCMath
|
||||
{
|
||||
return $this->powModOuter($e, $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*
|
||||
* Alias for modPow().
|
||||
*/
|
||||
public function powMod(BCMath $e, BCMath $n): BCMath
|
||||
{
|
||||
return $this->powModOuter($e, $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*/
|
||||
protected function powModInner(BCMath $e, BCMath $n): BCMath
|
||||
{
|
||||
try {
|
||||
$class = static::$modexpEngine[static::class];
|
||||
return $class::powModHelper($this, $e, $n, static::class);
|
||||
} catch (\Exception $err) {
|
||||
return BCMath\DefaultEngine::powModHelper($this, $e, $n, static::class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize
|
||||
*
|
||||
* Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
|
||||
*/
|
||||
protected function normalize(BCMath $result): BCMath
|
||||
{
|
||||
$result->precision = $this->precision;
|
||||
$result->bitmask = $this->bitmask;
|
||||
|
||||
if ($result->bitmask !== false) {
|
||||
$result->value = bcmod($result->value, $result->bitmask->value);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random prime number between a range
|
||||
*
|
||||
* If there's not a prime within the given range, false will be returned.
|
||||
*
|
||||
* @return false|BCMath
|
||||
*/
|
||||
public static function randomRangePrime(BCMath $min, BCMath $max)
|
||||
{
|
||||
return self::randomRangePrimeOuter($min, $max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random number between a range
|
||||
*
|
||||
* Returns a random number between $min and $max where $min and $max
|
||||
* can be defined using one of the two methods:
|
||||
*
|
||||
* BigInteger::randomRange($min, $max)
|
||||
* BigInteger::randomRange($max, $min)
|
||||
*/
|
||||
public static function randomRange(BCMath $min, BCMath $max): BCMath
|
||||
{
|
||||
return self::randomRangeHelper($min, $max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the current number odd
|
||||
*
|
||||
* If the current number is odd it'll be unchanged. If it's even, one will be added to it.
|
||||
*
|
||||
* @see self::randomPrime()
|
||||
*/
|
||||
protected function make_odd(): void
|
||||
{
|
||||
if (!$this->isOdd()) {
|
||||
$this->value = bcadd($this->value, '1');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the number against small primes.
|
||||
*
|
||||
* @see self::isPrime()
|
||||
*/
|
||||
protected function testSmallPrimes(): bool
|
||||
{
|
||||
if ($this->value === '1') {
|
||||
return false;
|
||||
}
|
||||
if ($this->value === '2') {
|
||||
return true;
|
||||
}
|
||||
if ($this->value[-1] % 2 == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = $this->value;
|
||||
|
||||
foreach (self::PRIMES as $prime) {
|
||||
$r = bcmod($this->value, (string)$prime);
|
||||
if ($r == '0') {
|
||||
return $this->value == $prime;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan for 1 and right shift by that amount
|
||||
*
|
||||
* ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
|
||||
*
|
||||
* @see self::isPrime()
|
||||
*/
|
||||
public static function scan1divide(BCMath $r): int
|
||||
{
|
||||
$r_value = &$r->value;
|
||||
$s = 0;
|
||||
// if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals(static::$one[static::class]) check earlier
|
||||
while ($r_value[-1] % 2 == 0) {
|
||||
$r_value = bcdiv($r_value, '2', 0);
|
||||
++$s;
|
||||
}
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs exponentiation.
|
||||
*/
|
||||
public function pow(BCMath $n): BCMath
|
||||
{
|
||||
$temp = new self();
|
||||
$temp->value = bcpow($this->value, $n->value);
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum BigInteger between an arbitrary number of BigIntegers.
|
||||
*/
|
||||
public static function min(BCMath ...$nums): BCMath
|
||||
{
|
||||
return self::minHelper($nums);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum BigInteger between an arbitrary number of BigIntegers.
|
||||
*/
|
||||
public static function max(BCMath ...$nums): BCMath
|
||||
{
|
||||
return self::maxHelper($nums);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests BigInteger to see if it is between two integers, inclusive
|
||||
*/
|
||||
public function between(BCMath $min, BCMath $max): bool
|
||||
{
|
||||
return $this->compare($min) >= 0 && $this->compare($max) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Bitmask
|
||||
*
|
||||
* @see self::setPrecision()
|
||||
*/
|
||||
protected static function setBitmask(int $bits): Engine
|
||||
{
|
||||
$temp = parent::setBitmask($bits);
|
||||
return $temp->add(static::$one[static::class]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Odd?
|
||||
*/
|
||||
public function isOdd(): bool
|
||||
{
|
||||
return $this->value[-1] % 2 == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a bit is set
|
||||
*/
|
||||
public function testBit($x): bool
|
||||
{
|
||||
return bccomp(
|
||||
bcmod($this->value, bcpow('2', $x + 1, 0)),
|
||||
bcpow('2', $x, 0),
|
||||
0
|
||||
) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Negative?
|
||||
*/
|
||||
public function isNegative(): bool
|
||||
{
|
||||
return strlen($this->value) && $this->value[0] == '-';
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate
|
||||
*
|
||||
* Given $k, returns -$k
|
||||
*/
|
||||
public function negate(): BCMath
|
||||
{
|
||||
$temp = clone $this;
|
||||
|
||||
if (!strlen($temp->value)) {
|
||||
return $temp;
|
||||
}
|
||||
|
||||
$temp->value = $temp->value[0] == '-' ?
|
||||
substr($this->value, 1) :
|
||||
'-' . $this->value;
|
||||
|
||||
return $temp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\BCMath;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\BCMath;
|
||||
|
||||
/**
|
||||
* Sliding Window Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class Base extends BCMath
|
||||
{
|
||||
/**
|
||||
* Cache constants
|
||||
*
|
||||
* $cache[self::VARIABLE] tells us whether or not the cached data is still valid.
|
||||
*/
|
||||
public const VARIABLE = 0;
|
||||
/**
|
||||
* $cache[self::DATA] contains the cached data.
|
||||
*/
|
||||
public const DATA = 1;
|
||||
|
||||
/**
|
||||
* Test for engine validity
|
||||
*/
|
||||
public static function isValidEngine(): bool
|
||||
{
|
||||
return static::class != __CLASS__;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*/
|
||||
protected static function powModHelper(BCMath $x, BCMath $e, BCMath $n, string $class): BCMath
|
||||
{
|
||||
if (empty($e->value)) {
|
||||
$temp = new $class();
|
||||
$temp->value = '1';
|
||||
return $x->normalize($temp);
|
||||
}
|
||||
|
||||
return $x->normalize(static::slidingWindow($x, $e, $n, $class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular reduction preparation
|
||||
*
|
||||
* @see self::slidingWindow()
|
||||
*/
|
||||
protected static function prepareReduce(string $x, string $n, string $class): string
|
||||
{
|
||||
return static::reduce($x, $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular multiply
|
||||
*
|
||||
* @see self::slidingWindow()
|
||||
*/
|
||||
protected static function multiplyReduce(string $x, string $y, string $n, string $class): string
|
||||
{
|
||||
return static::reduce(bcmul($x, $y), $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular square
|
||||
*
|
||||
* @see self::slidingWindow()
|
||||
*/
|
||||
protected static function squareReduce(string $x, string $n, string $class): string
|
||||
{
|
||||
return static::reduce(bcmul($x, $x), $n);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Built-In BCMath Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\BCMath;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\BCMath;
|
||||
|
||||
/**
|
||||
* Built-In BCMath Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class BuiltIn extends BCMath
|
||||
{
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*/
|
||||
protected static function powModHelper(BCMath $x, BCMath $e, BCMath $n): BCMath
|
||||
{
|
||||
$temp = new BCMath();
|
||||
$temp->value = bcpowmod($x->value, $e->value, $n->value);
|
||||
|
||||
return $x->normalize($temp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* BCMath Default Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\BCMath;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\BCMath\Reductions\Barrett;
|
||||
|
||||
/**
|
||||
* PHP Default Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class DefaultEngine extends Barrett
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* OpenSSL Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\BCMath;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\OpenSSL as Progenitor;
|
||||
|
||||
/**
|
||||
* OpenSSL Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class OpenSSL extends Progenitor
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* BCMath Barrett Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\BCMath\Reductions;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\BCMath\Base;
|
||||
|
||||
/**
|
||||
* PHP Barrett Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class Barrett extends Base
|
||||
{
|
||||
/**
|
||||
* Cache constants
|
||||
*
|
||||
* $cache[self::VARIABLE] tells us whether or not the cached data is still valid.
|
||||
*/
|
||||
public const VARIABLE = 0;
|
||||
/**
|
||||
* $cache[self::DATA] contains the cached data.
|
||||
*/
|
||||
public const DATA = 1;
|
||||
|
||||
/**
|
||||
* Barrett Modular Reduction
|
||||
*
|
||||
* See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
|
||||
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly,
|
||||
* so as not to require negative numbers (initially, this script didn't support negative numbers).
|
||||
*
|
||||
* Employs "folding", as described at
|
||||
* {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from
|
||||
* it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
|
||||
*
|
||||
* Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
|
||||
* usable on account of (1) its not using reasonable radix points as discussed in
|
||||
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
|
||||
* radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that
|
||||
* (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line
|
||||
* comments for details.
|
||||
*/
|
||||
protected static function reduce(string $n, string $m): string
|
||||
{
|
||||
static $cache = [
|
||||
self::VARIABLE => [],
|
||||
self::DATA => [],
|
||||
];
|
||||
|
||||
$m_length = strlen($m);
|
||||
|
||||
if (strlen($n) >= 2 * $m_length) {
|
||||
return bcmod($n, $m);
|
||||
}
|
||||
|
||||
// if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
|
||||
if ($m_length < 5) {
|
||||
return self::regularBarrett($n, $m);
|
||||
}
|
||||
// n = 2 * m.length
|
||||
|
||||
if (($key = array_search($m, $cache[self::VARIABLE])) === false) {
|
||||
$key = count($cache[self::VARIABLE]);
|
||||
$cache[self::VARIABLE][] = $m;
|
||||
|
||||
$lhs = '1' . str_repeat('0', $m_length + ($m_length >> 1));
|
||||
$u = bcdiv($lhs, $m, 0);
|
||||
$m1 = bcsub($lhs, bcmul($u, $m));
|
||||
|
||||
$cache[self::DATA][] = [
|
||||
'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
|
||||
'm1' => $m1, // m.length
|
||||
];
|
||||
} else {
|
||||
extract($cache[self::DATA][$key]);
|
||||
}
|
||||
|
||||
$cutoff = $m_length + ($m_length >> 1);
|
||||
|
||||
$lsd = substr($n, -$cutoff);
|
||||
$msd = substr($n, 0, -$cutoff);
|
||||
|
||||
$temp = bcmul($msd, $m1); // m.length + (m.length >> 1)
|
||||
$n = bcadd($lsd, $temp); // m.length + (m.length >> 1) + 1 (so basically we're adding two same length numbers)
|
||||
//if ($m_length & 1) {
|
||||
// return self::regularBarrett($n, $m);
|
||||
//}
|
||||
|
||||
// (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
|
||||
$temp = substr($n, 0, -$m_length + 1);
|
||||
// if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
|
||||
// if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
|
||||
$temp = bcmul($temp, $u);
|
||||
// if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
|
||||
// if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
|
||||
$temp = substr($temp, 0, -($m_length >> 1) - 1);
|
||||
// if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
|
||||
// if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1)
|
||||
$temp = bcmul($temp, $m);
|
||||
|
||||
// at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
|
||||
// number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop
|
||||
// following this comment would loop a lot (hence our calling _regularBarrett() in that situation).
|
||||
|
||||
$result = bcsub($n, $temp);
|
||||
|
||||
//if (bccomp($result, '0') < 0) {
|
||||
if ($result[0] == '-') {
|
||||
$temp = '1' . str_repeat('0', $m_length + 1);
|
||||
$result = bcadd($result, $temp);
|
||||
}
|
||||
|
||||
while (bccomp($result, $m) >= 0) {
|
||||
$result = bcsub($result, $m);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* (Regular) Barrett Modular Reduction
|
||||
*
|
||||
* For numbers with more than four digits BigInteger::_barrett() is faster. The difference between that and this
|
||||
* is that this function does not fold the denominator into a smaller form.
|
||||
*/
|
||||
private static function regularBarrett(string $x, string $n): string
|
||||
{
|
||||
static $cache = [
|
||||
self::VARIABLE => [],
|
||||
self::DATA => [],
|
||||
];
|
||||
|
||||
$n_length = strlen($n);
|
||||
|
||||
if (strlen($x) > 2 * $n_length) {
|
||||
return bcmod($x, $n);
|
||||
}
|
||||
|
||||
if (($key = array_search($n, $cache[self::VARIABLE])) === false) {
|
||||
$key = count($cache[self::VARIABLE]);
|
||||
$cache[self::VARIABLE][] = $n;
|
||||
$lhs = '1' . str_repeat('0', 2 * $n_length);
|
||||
$cache[self::DATA][] = bcdiv($lhs, $n, 0);
|
||||
}
|
||||
|
||||
$temp = substr($x, 0, -$n_length + 1);
|
||||
$temp = bcmul($temp, $cache[self::DATA][$key]);
|
||||
$temp = substr($temp, 0, -$n_length - 1);
|
||||
|
||||
$r1 = substr($x, -$n_length - 1);
|
||||
$r2 = substr(bcmul($temp, $n), -$n_length - 1);
|
||||
$result = bcsub($r1, $r2);
|
||||
|
||||
//if (bccomp($result, '0') < 0) {
|
||||
if ($result[0] == '-') {
|
||||
$q = '1' . str_repeat('0', $n_length + 1);
|
||||
$result = bcadd($result, $q);
|
||||
}
|
||||
|
||||
while (bccomp($result, $n) >= 0) {
|
||||
$result = bcsub($result, $n);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* BCMath Dynamic Barrett Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\BCMath\Reductions;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\BCMath;
|
||||
use phpseclib3\Math\BigInteger\Engines\BCMath\Base;
|
||||
|
||||
/**
|
||||
* PHP Barrett Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class EvalBarrett extends Base
|
||||
{
|
||||
/**
|
||||
* Custom Reduction Function
|
||||
*
|
||||
* @see self::generateCustomReduction
|
||||
*/
|
||||
private static $custom_reduction;
|
||||
|
||||
/**
|
||||
* Barrett Modular Reduction
|
||||
*
|
||||
* This calls a dynamically generated loop unrolled function that's specific to a given modulo.
|
||||
* Array lookups are avoided as are if statements testing for how many bits the host OS supports, etc.
|
||||
*/
|
||||
protected static function reduce(string $n, string $m): string
|
||||
{
|
||||
$inline = self::$custom_reduction;
|
||||
return $inline($n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Custom Reduction
|
||||
*
|
||||
* @return callable|void
|
||||
*/
|
||||
protected static function generateCustomReduction(BCMath $m, string $class)
|
||||
{
|
||||
$m_length = strlen($m);
|
||||
|
||||
if ($m_length < 5) {
|
||||
$code = 'return bcmod($x, $n);';
|
||||
eval('$func = function ($n) { ' . $code . '};');
|
||||
self::$custom_reduction = $func;
|
||||
return;
|
||||
}
|
||||
|
||||
$lhs = '1' . str_repeat('0', $m_length + ($m_length >> 1));
|
||||
$u = bcdiv($lhs, $m, 0);
|
||||
$m1 = bcsub($lhs, bcmul($u, $m));
|
||||
|
||||
$cutoff = $m_length + ($m_length >> 1);
|
||||
|
||||
$m = "'$m'";
|
||||
$u = "'$u'";
|
||||
$m1 = "'$m1'";
|
||||
|
||||
$code = '
|
||||
$lsd = substr($n, -' . $cutoff . ');
|
||||
$msd = substr($n, 0, -' . $cutoff . ');
|
||||
|
||||
$temp = bcmul($msd, ' . $m1 . ');
|
||||
$n = bcadd($lsd, $temp);
|
||||
|
||||
$temp = substr($n, 0, ' . (-$m_length + 1) . ');
|
||||
$temp = bcmul($temp, ' . $u . ');
|
||||
$temp = substr($temp, 0, ' . (-($m_length >> 1) - 1) . ');
|
||||
$temp = bcmul($temp, ' . $m . ');
|
||||
|
||||
$result = bcsub($n, $temp);
|
||||
|
||||
if ($result[0] == \'-\') {
|
||||
$temp = \'1' . str_repeat('0', $m_length + 1) . '\';
|
||||
$result = bcadd($result, $temp);
|
||||
}
|
||||
|
||||
while (bccomp($result, ' . $m . ') >= 0) {
|
||||
$result = bcsub($result, ' . $m . ');
|
||||
}
|
||||
|
||||
return $result;';
|
||||
|
||||
eval('$func = function ($n) { ' . $code . '};');
|
||||
|
||||
self::$custom_reduction = $func;
|
||||
|
||||
return $func;
|
||||
}
|
||||
}
|
||||
1219
qa-tool/htdocs/oidc/phpseclib/Math/BigInteger/Engines/Engine.php
Normal file
1219
qa-tool/htdocs/oidc/phpseclib/Math/BigInteger/Engines/Engine.php
Normal file
File diff suppressed because it is too large
Load Diff
591
qa-tool/htdocs/oidc/phpseclib/Math/BigInteger/Engines/GMP.php
Normal file
591
qa-tool/htdocs/oidc/phpseclib/Math/BigInteger/Engines/GMP.php
Normal file
@@ -0,0 +1,591 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* GMP BigInteger Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines;
|
||||
|
||||
use phpseclib3\Exception\BadConfigurationException;
|
||||
|
||||
/**
|
||||
* GMP Engine.
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class GMP extends Engine
|
||||
{
|
||||
/**
|
||||
* Can Bitwise operations be done fast?
|
||||
*
|
||||
* @see parent::bitwise_leftRotate()
|
||||
* @see parent::bitwise_rightRotate()
|
||||
*/
|
||||
public const FAST_BITWISE = true;
|
||||
|
||||
/**
|
||||
* Engine Directory
|
||||
*
|
||||
* @see parent::setModExpEngine
|
||||
*/
|
||||
public const ENGINE_DIR = 'GMP';
|
||||
|
||||
/**
|
||||
* Test for engine validity
|
||||
*
|
||||
* @see parent::__construct()
|
||||
*/
|
||||
public static function isValidEngine(): bool
|
||||
{
|
||||
return extension_loaded('gmp');
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param mixed $x integer Base-10 number or base-$base number if $base set.
|
||||
* @see parent::__construct()
|
||||
*/
|
||||
public function __construct($x = 0, int $base = 10)
|
||||
{
|
||||
if (!isset(static::$isValidEngine[static::class])) {
|
||||
static::$isValidEngine[static::class] = self::isValidEngine();
|
||||
}
|
||||
if (!static::$isValidEngine[static::class]) {
|
||||
throw new BadConfigurationException('GMP is not setup correctly on this system');
|
||||
}
|
||||
|
||||
if ($x instanceof \GMP) {
|
||||
$this->value = $x;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->value = gmp_init(0);
|
||||
|
||||
parent::__construct($x, $base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a GMP BigInteger Engine instance
|
||||
*
|
||||
* @see parent::__construct()
|
||||
*/
|
||||
protected function initialize(int $base): void
|
||||
{
|
||||
switch (abs($base)) {
|
||||
case 256:
|
||||
$this->value = gmp_import($this->value);
|
||||
if ($this->is_negative) {
|
||||
$this->value = -$this->value;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
$temp = $this->is_negative ? '-0x' . $this->value : '0x' . $this->value;
|
||||
$this->value = gmp_init($temp);
|
||||
break;
|
||||
case 10:
|
||||
$this->value = gmp_init($this->value ?? '0');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a BigInteger to a base-10 number.
|
||||
*/
|
||||
public function toString(): string
|
||||
{
|
||||
return (string)$this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a BigInteger to a bit string (eg. base-2).
|
||||
*
|
||||
* Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
|
||||
* saved as two's compliment.
|
||||
*/
|
||||
public function toBits(bool $twos_compliment = false): string
|
||||
{
|
||||
$hex = $this->toHex($twos_compliment);
|
||||
|
||||
$bits = gmp_strval(gmp_init($hex, 16), 2);
|
||||
|
||||
if ($this->precision > 0) {
|
||||
$bits = substr($bits, -$this->precision);
|
||||
}
|
||||
|
||||
if ($twos_compliment && $this->compare(new static()) > 0 && $this->precision <= 0) {
|
||||
return '0' . $bits;
|
||||
}
|
||||
|
||||
return $bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a BigInteger to a byte string (eg. base-256).
|
||||
*/
|
||||
public function toBytes(bool $twos_compliment = false): string
|
||||
{
|
||||
if ($twos_compliment) {
|
||||
return $this->toBytesHelper();
|
||||
}
|
||||
|
||||
if (gmp_cmp($this->value, gmp_init(0)) == 0) {
|
||||
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
|
||||
}
|
||||
|
||||
$temp = gmp_export($this->value);
|
||||
|
||||
return $this->precision > 0 ?
|
||||
substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
|
||||
ltrim($temp, chr(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two BigIntegers.
|
||||
*/
|
||||
public function add(GMP $y): GMP
|
||||
{
|
||||
$temp = new self();
|
||||
$temp->value = $this->value + $y->value;
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts two BigIntegers.
|
||||
*/
|
||||
public function subtract(GMP $y): GMP
|
||||
{
|
||||
$temp = new self();
|
||||
$temp->value = $this->value - $y->value;
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two BigIntegers.
|
||||
*/
|
||||
public function multiply(GMP $x): GMP
|
||||
{
|
||||
$temp = new self();
|
||||
$temp->value = $this->value * $x->value;
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (basically, the "common residue" is the first positive modulo).
|
||||
*
|
||||
* @return array{GMP, GMP}
|
||||
*/
|
||||
public function divide(GMP $y): array
|
||||
{
|
||||
$quotient = new self();
|
||||
$remainder = new self();
|
||||
|
||||
[$quotient->value, $remainder->value] = gmp_div_qr($this->value, $y->value);
|
||||
|
||||
if (gmp_sign($remainder->value) < 0) {
|
||||
$remainder->value = $remainder->value + gmp_abs($y->value);
|
||||
}
|
||||
|
||||
return [$this->normalize($quotient), $this->normalize($remainder)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two numbers.
|
||||
*
|
||||
* Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this
|
||||
* is demonstrated thusly:
|
||||
*
|
||||
* $x > $y: $x->compare($y) > 0
|
||||
* $x < $y: $x->compare($y) < 0
|
||||
* $x == $y: $x->compare($y) == 0
|
||||
*
|
||||
* Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
|
||||
*
|
||||
* {@internal Could return $this->subtract($x), but that's not as fast as what we do do.}
|
||||
*
|
||||
* @return int in case < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
|
||||
* @see self::equals()
|
||||
*/
|
||||
public function compare(GMP $y): int
|
||||
{
|
||||
$r = gmp_cmp($this->value, $y->value);
|
||||
if ($r < -1) {
|
||||
$r = -1;
|
||||
}
|
||||
if ($r > 1) {
|
||||
$r = 1;
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the equality of two numbers.
|
||||
*
|
||||
* If you need to see if one number is greater than or less than another number, use BigInteger::compare()
|
||||
*/
|
||||
public function equals(GMP $x): bool
|
||||
{
|
||||
return $this->value == $x->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates modular inverses.
|
||||
*
|
||||
* Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
|
||||
*
|
||||
* @return false|GMP
|
||||
*/
|
||||
public function modInverse(GMP $n)
|
||||
{
|
||||
$temp = new self();
|
||||
$temp->value = gmp_invert($this->value, $n->value);
|
||||
|
||||
return $temp->value === false ? false : $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 dependent 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.
|
||||
*
|
||||
* @return GMP[]
|
||||
*/
|
||||
public function extendedGCD(GMP $n): array
|
||||
{
|
||||
extract(gmp_gcdext($this->value, $n->value));
|
||||
|
||||
return [
|
||||
'gcd' => $this->normalize(new self($g)),
|
||||
'x' => $this->normalize(new self($s)),
|
||||
'y' => $this->normalize(new self($t)),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the greatest common divisor
|
||||
*
|
||||
* Say you have 693 and 609. The GCD is 21.
|
||||
*/
|
||||
public function gcd(GMP $n): GMP
|
||||
{
|
||||
$r = gmp_gcd($this->value, $n->value);
|
||||
return $this->normalize(new self($r));
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute value.
|
||||
*/
|
||||
public function abs(): GMP
|
||||
{
|
||||
$temp = new self();
|
||||
$temp->value = gmp_abs($this->value);
|
||||
|
||||
return $temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical And
|
||||
*/
|
||||
public function bitwise_and(GMP $x): GMP
|
||||
{
|
||||
$temp = new self();
|
||||
$temp->value = $this->value & $x->value;
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Or
|
||||
*/
|
||||
public function bitwise_or(GMP $x): GMP
|
||||
{
|
||||
$temp = new self();
|
||||
$temp->value = $this->value | $x->value;
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Exclusive Or
|
||||
*/
|
||||
public function bitwise_xor(GMP $x): GMP
|
||||
{
|
||||
$temp = new self();
|
||||
$temp->value = $this->value ^ $x->value;
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Right Shift
|
||||
*
|
||||
* Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
|
||||
*/
|
||||
public function bitwise_rightShift(int $shift): GMP
|
||||
{
|
||||
// 0xFFFFFFFF >> 2 == -1 (on 32-bit systems)
|
||||
// gmp_init('0xFFFFFFFF') >> 2 == gmp_init('0x3FFFFFFF')
|
||||
|
||||
$temp = new self();
|
||||
$temp->value = $this->value >> $shift;
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Left Shift
|
||||
*
|
||||
* Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
|
||||
*/
|
||||
public function bitwise_leftShift(int $shift): GMP
|
||||
{
|
||||
$temp = new self();
|
||||
$temp->value = $this->value << $shift;
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*/
|
||||
public function modPow(GMP $e, GMP $n): GMP
|
||||
{
|
||||
return $this->powModOuter($e, $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*
|
||||
* Alias for modPow().
|
||||
*/
|
||||
public function powMod(GMP $e, GMP $n): GMP
|
||||
{
|
||||
return $this->powModOuter($e, $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*/
|
||||
protected function powModInner(GMP $e, GMP $n): GMP
|
||||
{
|
||||
$class = static::$modexpEngine[static::class];
|
||||
return $class::powModHelper($this, $e, $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize
|
||||
*
|
||||
* Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
|
||||
*/
|
||||
protected function normalize(GMP $result): GMP
|
||||
{
|
||||
$result->precision = $this->precision;
|
||||
$result->bitmask = $this->bitmask;
|
||||
|
||||
if ($result->bitmask !== false) {
|
||||
$flip = $result->value < 0;
|
||||
if ($flip) {
|
||||
$result->value = -$result->value;
|
||||
}
|
||||
$result->value = $result->value & $result->bitmask->value;
|
||||
if ($flip) {
|
||||
$result->value = -$result->value;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs some post-processing for randomRangePrime
|
||||
*
|
||||
* @return GMP
|
||||
*/
|
||||
protected static function randomRangePrimeInner(Engine $x, Engine $min, Engine $max)
|
||||
{
|
||||
$p = gmp_nextprime($x->value);
|
||||
|
||||
if ($p <= $max->value) {
|
||||
return new self($p);
|
||||
}
|
||||
|
||||
if ($min->value != $x->value) {
|
||||
$x = new self($x->value - 1);
|
||||
}
|
||||
|
||||
return self::randomRangePrime($min, $x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random prime number between a range
|
||||
*
|
||||
* If there's not a prime within the given range, false will be returned.
|
||||
*
|
||||
* @return false|GMP
|
||||
*/
|
||||
public static function randomRangePrime(GMP $min, GMP $max)
|
||||
{
|
||||
return self::randomRangePrimeOuter($min, $max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random number between a range
|
||||
*
|
||||
* Returns a random number between $min and $max where $min and $max
|
||||
* can be defined using one of the two methods:
|
||||
*
|
||||
* BigInteger::randomRange($min, $max)
|
||||
* BigInteger::randomRange($max, $min)
|
||||
*/
|
||||
public static function randomRange(GMP $min, GMP $max): GMP
|
||||
{
|
||||
return self::randomRangeHelper($min, $max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the current number odd
|
||||
*
|
||||
* If the current number is odd it'll be unchanged. If it's even, one will be added to it.
|
||||
*
|
||||
* @see self::randomPrime()
|
||||
*/
|
||||
protected function make_odd(): void
|
||||
{
|
||||
gmp_setbit($this->value, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests Primality
|
||||
*/
|
||||
protected function testPrimality(int $t): bool
|
||||
{
|
||||
return gmp_prob_prime($this->value, $t) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the nth root of a biginteger.
|
||||
*
|
||||
* Returns the nth root of a positive biginteger, where n defaults to 2
|
||||
*/
|
||||
protected function rootInner(int $n): GMP
|
||||
{
|
||||
$root = new self();
|
||||
$root->value = gmp_root($this->value, $n);
|
||||
return $this->normalize($root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs exponentiation.
|
||||
*/
|
||||
public function pow(GMP $n): GMP
|
||||
{
|
||||
$temp = new self();
|
||||
$temp->value = $this->value ** $n->value;
|
||||
|
||||
return $this->normalize($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum BigInteger between an arbitrary number of BigIntegers.
|
||||
*/
|
||||
public static function min(GMP ...$nums): GMP
|
||||
{
|
||||
return self::minHelper($nums);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum BigInteger between an arbitrary number of BigIntegers.
|
||||
*/
|
||||
public static function max(GMP ...$nums): GMP
|
||||
{
|
||||
return self::maxHelper($nums);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests BigInteger to see if it is between two integers, inclusive
|
||||
*/
|
||||
public function between(GMP $min, GMP $max): bool
|
||||
{
|
||||
return $this->compare($min) >= 0 && $this->compare($max) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Recurring Modulo Function
|
||||
*
|
||||
* Sometimes it may be desirable to do repeated modulos with the same number outside of
|
||||
* modular exponentiation
|
||||
*/
|
||||
public function createRecurringModuloFunction(): \Closure
|
||||
{
|
||||
$temp = $this->value;
|
||||
return fn (GMP $x) => new GMP($x->value % $temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan for 1 and right shift by that amount
|
||||
*
|
||||
* ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
|
||||
*/
|
||||
public static function scan1divide(GMP $r): int
|
||||
{
|
||||
$s = gmp_scan1($r->value, 0);
|
||||
$r->value >>= $s;
|
||||
return $s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Odd?
|
||||
*/
|
||||
public function isOdd(): bool
|
||||
{
|
||||
return gmp_testbit($this->value, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a bit is set
|
||||
*/
|
||||
public function testBit($x): bool
|
||||
{
|
||||
return gmp_testbit($this->value, $x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Negative?
|
||||
*/
|
||||
public function isNegative(): bool
|
||||
{
|
||||
return gmp_sign($this->value) == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate
|
||||
*
|
||||
* Given $k, returns -$k
|
||||
*/
|
||||
public function negate(): GMP
|
||||
{
|
||||
$temp = clone $this;
|
||||
$temp->value = -$this->value;
|
||||
|
||||
return $temp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* GMP Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\GMP;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\GMP;
|
||||
|
||||
/**
|
||||
* GMP Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class DefaultEngine extends GMP
|
||||
{
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*/
|
||||
protected static function powModHelper(GMP $x, GMP $e, GMP $n): GMP
|
||||
{
|
||||
$temp = new GMP();
|
||||
$temp->value = gmp_powm($x->value, $e->value, $n->value);
|
||||
|
||||
return $x->normalize($temp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* OpenSSL Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines;
|
||||
|
||||
use phpseclib3\Crypt\RSA\Formats\Keys\PKCS8;
|
||||
use phpseclib3\Exception\OutOfRangeException;
|
||||
use phpseclib3\Exception\UnexpectedValueException;
|
||||
use phpseclib3\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* OpenSSL Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class OpenSSL
|
||||
{
|
||||
/**
|
||||
* Test for engine validity
|
||||
*/
|
||||
public static function isValidEngine(): bool
|
||||
{
|
||||
return extension_loaded('openssl') && static::class != __CLASS__;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*/
|
||||
public static function powModHelper(Engine $x, Engine $e, Engine $n): Engine
|
||||
{
|
||||
if ($n->getLengthInBytes() < 31 || $n->getLengthInBytes() > 16384) {
|
||||
throw new OutOfRangeException('Only modulo between 31 and 16384 bits are accepted');
|
||||
}
|
||||
|
||||
$key = PKCS8::savePublicKey(
|
||||
new BigInteger($n),
|
||||
new BigInteger($e)
|
||||
);
|
||||
|
||||
$plaintext = str_pad($x->toBytes(), $n->getLengthInBytes(), "\0", STR_PAD_LEFT);
|
||||
|
||||
// this is easily prone to failure. if the modulo is a multiple of 2 or 3 or whatever it
|
||||
// won't work and you'll get a "failure: error:0906D06C:PEM routines:PEM_read_bio:no start line"
|
||||
// error. i suppose, for even numbers, we could do what PHP\Montgomery.php does, but then what
|
||||
// about odd numbers divisible by 3, by 5, etc?
|
||||
if (!openssl_public_encrypt($plaintext, $result, $key, OPENSSL_NO_PADDING)) {
|
||||
throw new UnexpectedValueException(openssl_error_string());
|
||||
}
|
||||
|
||||
$class = $x::class;
|
||||
return new $class($result, 256);
|
||||
}
|
||||
}
|
||||
1265
qa-tool/htdocs/oidc/phpseclib/Math/BigInteger/Engines/PHP.php
Normal file
1265
qa-tool/htdocs/oidc/phpseclib/Math/BigInteger/Engines/PHP.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\PHP;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\PHP;
|
||||
|
||||
/**
|
||||
* PHP Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class Base extends PHP
|
||||
{
|
||||
/**
|
||||
* Cache constants
|
||||
*
|
||||
* $cache[self::VARIABLE] tells us whether or not the cached data is still valid.
|
||||
*/
|
||||
public const VARIABLE = 0;
|
||||
/**
|
||||
* $cache[self::DATA] contains the cached data.
|
||||
*/
|
||||
public const DATA = 1;
|
||||
|
||||
/**
|
||||
* Test for engine validity
|
||||
*/
|
||||
public static function isValidEngine(): bool
|
||||
{
|
||||
return static::class != __CLASS__;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*
|
||||
* The most naive approach to modular exponentiation has very unreasonable requirements, and
|
||||
* and although the approach involving repeated squaring does vastly better, it, too, is impractical
|
||||
* for our purposes. The reason being that division - by far the most complicated and time-consuming
|
||||
* of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
|
||||
*
|
||||
* Modular reductions resolve this issue. Although an individual modular reduction takes more time
|
||||
* then an individual division, when performed in succession (with the same modulo), they're a lot faster.
|
||||
*
|
||||
* The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction,
|
||||
* although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the
|
||||
* base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
|
||||
* the product of two odd numbers is odd), but what about when RSA isn't used?
|
||||
*
|
||||
* In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a
|
||||
* Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the
|
||||
* modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however,
|
||||
* uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
|
||||
* the other, a power of two - and recombine them, later. This is the method that this modPow function uses.
|
||||
* {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
|
||||
*/
|
||||
protected static function powModHelper(PHP $x, PHP $e, PHP $n, string $class): PHP
|
||||
{
|
||||
if (empty($e->value)) {
|
||||
$temp = new $class();
|
||||
$temp->value = [1];
|
||||
return $x->normalize($temp);
|
||||
}
|
||||
|
||||
if ($e->value == [1]) {
|
||||
[, $temp] = $x->divide($n);
|
||||
return $x->normalize($temp);
|
||||
}
|
||||
|
||||
if ($e->value == [2]) {
|
||||
$temp = new $class();
|
||||
$temp->value = $class::square($x->value);
|
||||
[, $temp] = $temp->divide($n);
|
||||
return $x->normalize($temp);
|
||||
}
|
||||
|
||||
return $x->normalize(static::slidingWindow($x, $e, $n, $class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular reduction preparation
|
||||
*
|
||||
* @see self::slidingWindow()
|
||||
*/
|
||||
protected static function prepareReduce(array $x, array $n, string $class): array
|
||||
{
|
||||
return static::reduce($x, $n, $class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular multiply
|
||||
*
|
||||
* @see self::slidingWindow()
|
||||
*/
|
||||
protected static function multiplyReduce(array $x, array $y, array $n, string $class): array
|
||||
{
|
||||
$temp = $class::multiplyHelper($x, false, $y, false);
|
||||
return static::reduce($temp[self::VALUE], $n, $class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular square
|
||||
*
|
||||
* @see self::slidingWindow()
|
||||
*/
|
||||
protected static function squareReduce(array $x, array $n, string $class): array
|
||||
{
|
||||
return static::reduce($class::square($x), $n, $class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Default Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\PHP;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\PHP\Reductions\EvalBarrett;
|
||||
|
||||
/**
|
||||
* PHP Default Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class DefaultEngine extends EvalBarrett
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Montgomery Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\PHP;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\Engine;
|
||||
use phpseclib3\Math\BigInteger\Engines\PHP;
|
||||
use phpseclib3\Math\BigInteger\Engines\PHP\Reductions\PowerOfTwo;
|
||||
|
||||
/**
|
||||
* PHP Montgomery Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class Montgomery extends Base
|
||||
{
|
||||
/**
|
||||
* Test for engine validity
|
||||
*/
|
||||
public static function isValidEngine(): bool
|
||||
{
|
||||
return static::class != __CLASS__;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*
|
||||
* @template T of Engine
|
||||
* @param class-string<T> $class
|
||||
* @return T
|
||||
*/
|
||||
protected static function slidingWindow(Engine $x, Engine $e, Engine $n, string $class)
|
||||
{
|
||||
// is the modulo odd?
|
||||
if ($n->value[0] & 1) {
|
||||
return parent::slidingWindow($x, $e, $n, $class);
|
||||
}
|
||||
// if it's not, it's even
|
||||
|
||||
// find the lowest set bit (eg. the max pow of 2 that divides $n)
|
||||
for ($i = 0; $i < count($n->value); ++$i) {
|
||||
if ($n->value[$i]) {
|
||||
$temp = decbin($n->value[$i]);
|
||||
$j = strlen($temp) - strrpos($temp, '1') - 1;
|
||||
$j += $class::BASE * $i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// at this point, 2^$j * $n/(2^$j) == $n
|
||||
|
||||
$mod1 = clone $n;
|
||||
$mod1->rshift($j);
|
||||
$mod2 = new $class();
|
||||
$mod2->value = [1];
|
||||
$mod2->lshift($j);
|
||||
|
||||
$part1 = $mod1->value != [1] ? parent::slidingWindow($x, $e, $mod1, $class) : new $class();
|
||||
$part2 = PowerOfTwo::slidingWindow($x, $e, $mod2, $class);
|
||||
|
||||
$y1 = $mod2->modInverse($mod1);
|
||||
$y2 = $mod1->modInverse($mod2);
|
||||
|
||||
$result = $part1->multiply($mod2);
|
||||
$result = $result->multiply($y1);
|
||||
|
||||
$temp = $part2->multiply($mod1);
|
||||
$temp = $temp->multiply($y2);
|
||||
|
||||
$result = $result->add($temp);
|
||||
[, $result] = $result->divide($n);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* OpenSSL Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\PHP;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\OpenSSL as Progenitor;
|
||||
|
||||
/**
|
||||
* OpenSSL Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class OpenSSL extends Progenitor
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Barrett Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\PHP\Reductions;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\PHP;
|
||||
use phpseclib3\Math\BigInteger\Engines\PHP\Base;
|
||||
|
||||
/**
|
||||
* PHP Barrett Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class Barrett extends Base
|
||||
{
|
||||
/**
|
||||
* Barrett Modular Reduction
|
||||
*
|
||||
* See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
|
||||
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly,
|
||||
* so as not to require negative numbers (initially, this script didn't support negative numbers).
|
||||
*
|
||||
* Employs "folding", as described at
|
||||
* {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from
|
||||
* it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
|
||||
*
|
||||
* Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
|
||||
* usable on account of (1) its not using reasonable radix points as discussed in
|
||||
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
|
||||
* radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that
|
||||
* (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line
|
||||
* comments for details.
|
||||
*
|
||||
* @param class-string<PHP> $class
|
||||
*/
|
||||
protected static function reduce(array $n, array $m, string $class): array
|
||||
{
|
||||
static $cache = [
|
||||
self::VARIABLE => [],
|
||||
self::DATA => [],
|
||||
];
|
||||
|
||||
$m_length = count($m);
|
||||
|
||||
// if (self::compareHelper($n, $static::square($m)) >= 0) {
|
||||
if (count($n) >= 2 * $m_length) {
|
||||
$lhs = new $class();
|
||||
$rhs = new $class();
|
||||
$lhs->value = $n;
|
||||
$rhs->value = $m;
|
||||
[, $temp] = $lhs->divide($rhs);
|
||||
return $temp->value;
|
||||
}
|
||||
|
||||
// if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
|
||||
if ($m_length < 5) {
|
||||
return self::regularBarrett($n, $m, $class);
|
||||
}
|
||||
// n = 2 * m.length
|
||||
|
||||
if (($key = array_search($m, $cache[self::VARIABLE])) === false) {
|
||||
$key = count($cache[self::VARIABLE]);
|
||||
$cache[self::VARIABLE][] = $m;
|
||||
|
||||
$lhs = new $class();
|
||||
$lhs_value = &$lhs->value;
|
||||
$lhs_value = self::array_repeat(0, $m_length + ($m_length >> 1));
|
||||
$lhs_value[] = 1;
|
||||
$rhs = new $class();
|
||||
$rhs->value = $m;
|
||||
|
||||
[$u, $m1] = $lhs->divide($rhs);
|
||||
$u = $u->value;
|
||||
$m1 = $m1->value;
|
||||
|
||||
$cache[self::DATA][] = [
|
||||
'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
|
||||
'm1' => $m1, // m.length
|
||||
];
|
||||
} else {
|
||||
extract($cache[self::DATA][$key]);
|
||||
}
|
||||
|
||||
$cutoff = $m_length + ($m_length >> 1);
|
||||
$lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)
|
||||
$msd = array_slice($n, $cutoff); // m.length >> 1
|
||||
|
||||
$lsd = self::trim($lsd);
|
||||
$temp = $class::multiplyHelper($msd, false, $m1, false); // m.length + (m.length >> 1)
|
||||
$n = $class::addHelper($lsd, false, $temp[self::VALUE], false); // m.length + (m.length >> 1) + 1 (so basically we're adding two same length numbers)
|
||||
//if ($m_length & 1) {
|
||||
// return self::regularBarrett($n[self::VALUE], $m, $class);
|
||||
//}
|
||||
|
||||
// (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
|
||||
$temp = array_slice($n[self::VALUE], $m_length - 1);
|
||||
// if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
|
||||
// if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
|
||||
$temp = $class::multiplyHelper($temp, false, $u, false);
|
||||
// if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
|
||||
// if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
|
||||
$temp = array_slice($temp[self::VALUE], ($m_length >> 1) + 1);
|
||||
// if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
|
||||
// if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1)
|
||||
$temp = $class::multiplyHelper($temp, false, $m, false);
|
||||
|
||||
// at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
|
||||
// number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop
|
||||
// following this comment would loop a lot (hence our calling _regularBarrett() in that situation).
|
||||
|
||||
$result = $class::subtractHelper($n[self::VALUE], false, $temp[self::VALUE], false);
|
||||
|
||||
while (self::compareHelper($result[self::VALUE], $result[self::SIGN], $m, false) >= 0) {
|
||||
$result = $class::subtractHelper($result[self::VALUE], $result[self::SIGN], $m, false);
|
||||
}
|
||||
|
||||
return $result[self::VALUE];
|
||||
}
|
||||
|
||||
/**
|
||||
* (Regular) Barrett Modular Reduction
|
||||
*
|
||||
* For numbers with more than four digits BigInteger::_barrett() is faster. The difference between that and this
|
||||
* is that this function does not fold the denominator into a smaller form.
|
||||
*/
|
||||
private static function regularBarrett(array $x, array $n, string $class): array
|
||||
{
|
||||
static $cache = [
|
||||
self::VARIABLE => [],
|
||||
self::DATA => [],
|
||||
];
|
||||
|
||||
$n_length = count($n);
|
||||
|
||||
if (count($x) > 2 * $n_length) {
|
||||
$lhs = new $class();
|
||||
$rhs = new $class();
|
||||
$lhs->value = $x;
|
||||
$rhs->value = $n;
|
||||
[, $temp] = $lhs->divide($rhs);
|
||||
return $temp->value;
|
||||
}
|
||||
|
||||
if (($key = array_search($n, $cache[self::VARIABLE])) === false) {
|
||||
$key = count($cache[self::VARIABLE]);
|
||||
$cache[self::VARIABLE][] = $n;
|
||||
$lhs = new $class();
|
||||
$lhs_value = &$lhs->value;
|
||||
$lhs_value = self::array_repeat(0, 2 * $n_length);
|
||||
$lhs_value[] = 1;
|
||||
$rhs = new $class();
|
||||
$rhs->value = $n;
|
||||
[$temp, ] = $lhs->divide($rhs); // m.length
|
||||
$cache[self::DATA][] = $temp->value;
|
||||
}
|
||||
|
||||
// 2 * m.length - (m.length - 1) = m.length + 1
|
||||
$temp = array_slice($x, $n_length - 1);
|
||||
// (m.length + 1) + m.length = 2 * m.length + 1
|
||||
$temp = $class::multiplyHelper($temp, false, $cache[self::DATA][$key], false);
|
||||
// (2 * m.length + 1) - (m.length - 1) = m.length + 2
|
||||
$temp = array_slice($temp[self::VALUE], $n_length + 1);
|
||||
|
||||
// m.length + 1
|
||||
$result = array_slice($x, 0, $n_length + 1);
|
||||
// m.length + 1
|
||||
$temp = self::multiplyLower($temp, false, $n, false, $n_length + 1, $class);
|
||||
// $temp == array_slice($class::regularMultiply($temp, false, $n, false)->value, 0, $n_length + 1)
|
||||
|
||||
if (self::compareHelper($result, false, $temp[self::VALUE], $temp[self::SIGN]) < 0) {
|
||||
$corrector_value = self::array_repeat(0, $n_length + 1);
|
||||
$corrector_value[count($corrector_value)] = 1;
|
||||
$result = $class::addHelper($result, false, $corrector_value, false);
|
||||
$result = $result[self::VALUE];
|
||||
}
|
||||
|
||||
// at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits
|
||||
$result = $class::subtractHelper($result, false, $temp[self::VALUE], $temp[self::SIGN]);
|
||||
while (self::compareHelper($result[self::VALUE], $result[self::SIGN], $n, false) > 0) {
|
||||
$result = $class::subtractHelper($result[self::VALUE], $result[self::SIGN], $n, false);
|
||||
}
|
||||
|
||||
return $result[self::VALUE];
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs long multiplication up to $stop digits
|
||||
*
|
||||
* If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
|
||||
*
|
||||
* @see self::regularBarrett()
|
||||
*/
|
||||
private static function multiplyLower(array $x_value, bool $x_negative, array $y_value, bool $y_negative, int $stop, string $class): array
|
||||
{
|
||||
$x_length = count($x_value);
|
||||
$y_length = count($y_value);
|
||||
|
||||
if (!$x_length || !$y_length) { // a 0 is being multiplied
|
||||
return [
|
||||
self::VALUE => [],
|
||||
self::SIGN => false,
|
||||
];
|
||||
}
|
||||
|
||||
if ($x_length < $y_length) {
|
||||
$temp = $x_value;
|
||||
$x_value = $y_value;
|
||||
$y_value = $temp;
|
||||
|
||||
$x_length = count($x_value);
|
||||
$y_length = count($y_value);
|
||||
}
|
||||
|
||||
$product_value = self::array_repeat(0, $x_length + $y_length);
|
||||
|
||||
// the following for loop could be removed if the for loop following it
|
||||
// (the one with nested for loops) initially set $i to 0, but
|
||||
// doing so would also make the result in one set of unnecessary adds,
|
||||
// since on the outermost loops first pass, $product->value[$k] is going
|
||||
// to always be 0
|
||||
|
||||
$carry = 0;
|
||||
|
||||
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
|
||||
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
|
||||
$carry = $class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
|
||||
$product_value[$j] = (int) ($temp - $class::BASE_FULL * $carry);
|
||||
}
|
||||
|
||||
if ($j < $stop) {
|
||||
$product_value[$j] = $carry;
|
||||
}
|
||||
|
||||
// the above for loop is what the previous comment was talking about. the
|
||||
// following for loop is the "one with nested for loops"
|
||||
|
||||
for ($i = 1; $i < $y_length; ++$i) {
|
||||
$carry = 0;
|
||||
|
||||
for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
|
||||
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
|
||||
$carry = $class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
|
||||
$product_value[$k] = (int) ($temp - $class::BASE_FULL * $carry);
|
||||
}
|
||||
|
||||
if ($k < $stop) {
|
||||
$product_value[$k] = $carry;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
self::VALUE => self::trim($product_value),
|
||||
self::SIGN => $x_negative != $y_negative,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Classic Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\PHP\Reductions;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\PHP\Base;
|
||||
|
||||
/**
|
||||
* PHP Classic Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class Classic extends Base
|
||||
{
|
||||
/**
|
||||
* Regular Division
|
||||
*/
|
||||
protected static function reduce(array $x, array $n, string $class): array
|
||||
{
|
||||
$lhs = new $class();
|
||||
$lhs->value = $x;
|
||||
$rhs = new $class();
|
||||
$rhs->value = $n;
|
||||
[, $temp] = $lhs->divide($rhs);
|
||||
return $temp->value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,444 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Dynamic Barrett Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\PHP\Reductions;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\PHP;
|
||||
use phpseclib3\Math\BigInteger\Engines\PHP\Base;
|
||||
|
||||
/**
|
||||
* PHP Dynamic Barrett Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class EvalBarrett extends Base
|
||||
{
|
||||
/**
|
||||
* Custom Reduction Function
|
||||
*
|
||||
* @see self::generateCustomReduction
|
||||
*/
|
||||
private static $custom_reduction;
|
||||
|
||||
/**
|
||||
* Barrett Modular Reduction
|
||||
*
|
||||
* This calls a dynamically generated loop unrolled function that's specific to a given modulo.
|
||||
* Array lookups are avoided as are if statements testing for how many bits the host OS supports, etc.
|
||||
*/
|
||||
protected static function reduce(array $n, array $m, string $class): array
|
||||
{
|
||||
$inline = self::$custom_reduction;
|
||||
return $inline($n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate Custom Reduction
|
||||
*/
|
||||
protected static function generateCustomReduction(PHP $m, string $class): callable
|
||||
{
|
||||
$m_length = count($m->value);
|
||||
|
||||
if ($m_length < 5) {
|
||||
$code = '
|
||||
$lhs = new ' . $class . '();
|
||||
$lhs->value = $x;
|
||||
$rhs = new ' . $class . '();
|
||||
$rhs->value = [' .
|
||||
implode(',', array_map(self::class . '::float2string', $m->value)) . '];
|
||||
list(, $temp) = $lhs->divide($rhs);
|
||||
return $temp->value;
|
||||
';
|
||||
eval('$func = function ($x) { ' . $code . '};');
|
||||
self::$custom_reduction = $func;
|
||||
//self::$custom_reduction = \Closure::bind($func, $m, $class);
|
||||
return $func;
|
||||
}
|
||||
|
||||
$lhs = new $class();
|
||||
$lhs_value = &$lhs->value;
|
||||
|
||||
$lhs_value = self::array_repeat(0, $m_length + ($m_length >> 1));
|
||||
$lhs_value[] = 1;
|
||||
$rhs = new $class();
|
||||
|
||||
[$u, $m1] = $lhs->divide($m);
|
||||
|
||||
if ($class::BASE != 26) {
|
||||
$u = $u->value;
|
||||
} else {
|
||||
$lhs_value = self::array_repeat(0, 2 * $m_length);
|
||||
$lhs_value[] = 1;
|
||||
$rhs = new $class();
|
||||
|
||||
[$u] = $lhs->divide($m);
|
||||
$u = $u->value;
|
||||
}
|
||||
|
||||
$m = $m->value;
|
||||
$m1 = $m1->value;
|
||||
|
||||
$cutoff = count($m) + (count($m) >> 1);
|
||||
|
||||
$code = '
|
||||
if (count($n) >= ' . (2 * count($m)) . ') {
|
||||
$lhs = new ' . $class . '();
|
||||
$rhs = new ' . $class . '();
|
||||
$lhs->value = $n;
|
||||
$rhs->value = [' .
|
||||
implode(',', array_map(self::class . '::float2string', $m)) . '];
|
||||
list(, $temp) = $lhs->divide($rhs);
|
||||
return $temp->value;
|
||||
}
|
||||
|
||||
$lsd = array_slice($n, 0, ' . $cutoff . ');
|
||||
$msd = array_slice($n, ' . $cutoff . ');';
|
||||
|
||||
$code .= self::generateInlineTrim('msd');
|
||||
$code .= self::generateInlineMultiply('msd', $m1, 'temp', $class);
|
||||
$code .= self::generateInlineAdd('lsd', 'temp', 'n', $class);
|
||||
|
||||
$code .= '$temp = array_slice($n, ' . (count($m) - 1) . ');';
|
||||
$code .= self::generateInlineMultiply('temp', $u, 'temp2', $class);
|
||||
$code .= self::generateInlineTrim('temp2');
|
||||
|
||||
$code .= $class::BASE == 26 ?
|
||||
'$temp = array_slice($temp2, ' . (count($m) + 1) . ');' :
|
||||
'$temp = array_slice($temp2, ' . ((count($m) >> 1) + 1) . ');';
|
||||
$code .= self::generateInlineMultiply('temp', $m, 'temp2', $class);
|
||||
$code .= self::generateInlineTrim('temp2');
|
||||
|
||||
/*
|
||||
if ($class::BASE == 26) {
|
||||
$code.= '$n = array_slice($n, 0, ' . (count($m) + 1) . ');
|
||||
$temp2 = array_slice($temp2, 0, ' . (count($m) + 1) . ');';
|
||||
}
|
||||
*/
|
||||
|
||||
$code .= self::generateInlineSubtract2('n', 'temp2', 'temp', $class);
|
||||
|
||||
$subcode = self::generateInlineSubtract1('temp', $m, 'temp2', $class);
|
||||
$subcode .= '$temp = $temp2;';
|
||||
|
||||
$code .= self::generateInlineCompare($m, 'temp', $subcode);
|
||||
|
||||
$code .= 'return $temp;';
|
||||
|
||||
eval('$func = function ($n) { ' . $code . '};');
|
||||
|
||||
self::$custom_reduction = $func;
|
||||
|
||||
return $func;
|
||||
|
||||
//self::$custom_reduction = \Closure::bind($func, $m, $class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline Trim
|
||||
*
|
||||
* Removes leading zeros
|
||||
*/
|
||||
private static function generateInlineTrim(string $name): string
|
||||
{
|
||||
return '
|
||||
for ($i = count($' . $name . ') - 1; $i >= 0; --$i) {
|
||||
if ($' . $name . '[$i]) {
|
||||
break;
|
||||
}
|
||||
unset($' . $name . '[$i]);
|
||||
}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline Multiply (unknown, known)
|
||||
*/
|
||||
private static function generateInlineMultiply(string $input, array $arr, string $output, string $class): string
|
||||
{
|
||||
if (!count($arr)) {
|
||||
return 'return [];';
|
||||
}
|
||||
|
||||
$regular = '
|
||||
$length = count($' . $input . ');
|
||||
if (!$length) {
|
||||
$' . $output . ' = [];
|
||||
}else{
|
||||
$' . $output . ' = array_fill(0, $length + ' . count($arr) . ', 0);
|
||||
$carry = 0;';
|
||||
|
||||
for ($i = 0; $i < count($arr); $i++) {
|
||||
$regular .= '
|
||||
$subtemp = $' . $input . '[0] * ' . $arr[$i];
|
||||
$regular .= $i ? ' + $carry;' : ';';
|
||||
|
||||
$regular .= '$carry = ';
|
||||
$regular .= $class::BASE === 26 ?
|
||||
'intval($subtemp / 0x4000000);' :
|
||||
'$subtemp >> 31;';
|
||||
$regular .=
|
||||
'$' . $output . '[' . $i . '] = ';
|
||||
if ($class::BASE === 26) {
|
||||
$regular .= '(int) (';
|
||||
}
|
||||
$regular .= '$subtemp - ' . $class::BASE_FULL . ' * $carry';
|
||||
$regular .= $class::BASE === 26 ? ');' : ';';
|
||||
}
|
||||
|
||||
$regular .= '$' . $output . '[' . count($arr) . '] = $carry;';
|
||||
|
||||
$regular .= '
|
||||
for ($i = 1; $i < $length; ++$i) {';
|
||||
|
||||
for ($j = 0; $j < count($arr); $j++) {
|
||||
$regular .= $j ? '$k++;' : '$k = $i;';
|
||||
$regular .= '
|
||||
$subtemp = $' . $output . '[$k] + $' . $input . '[$i] * ' . $arr[$j];
|
||||
$regular .= $j ? ' + $carry;' : ';';
|
||||
|
||||
$regular .= '$carry = ';
|
||||
$regular .= $class::BASE === 26 ?
|
||||
'intval($subtemp / 0x4000000);' :
|
||||
'$subtemp >> 31;';
|
||||
$regular .=
|
||||
'$' . $output . '[$k] = ';
|
||||
if ($class::BASE === 26) {
|
||||
$regular .= '(int) (';
|
||||
}
|
||||
$regular .= '$subtemp - ' . $class::BASE_FULL . ' * $carry';
|
||||
$regular .= $class::BASE === 26 ? ');' : ';';
|
||||
}
|
||||
|
||||
$regular .= '$' . $output . '[++$k] = $carry; $carry = 0;';
|
||||
|
||||
$regular .= '}}';
|
||||
|
||||
//if (count($arr) < 2 * self::KARATSUBA_CUTOFF) {
|
||||
//}
|
||||
|
||||
return $regular;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline Addition
|
||||
*/
|
||||
private static function generateInlineAdd(string $x, string $y, string $result, string $class): string
|
||||
{
|
||||
$code = '
|
||||
$length = max(count($' . $x . '), count($' . $y . '));
|
||||
$' . $result . ' = array_pad($' . $x . ', $length + 1, 0);
|
||||
$_' . $y . ' = array_pad($' . $y . ', $length, 0);
|
||||
$carry = 0;
|
||||
for ($i = 0, $j = 1; $j < $length; $i+=2, $j+=2) {
|
||||
$sum = ($' . $result . '[$j] + $_' . $y . '[$j]) * ' . $class::BASE_FULL . '
|
||||
+ $' . $result . '[$i] + $_' . $y . '[$i] +
|
||||
$carry;
|
||||
$carry = $sum >= ' . self::float2string($class::MAX_DIGIT2) . ';
|
||||
$sum = $carry ? $sum - ' . self::float2string($class::MAX_DIGIT2) . ' : $sum;';
|
||||
|
||||
$code .= $class::BASE === 26 ?
|
||||
'$upper = intval($sum / 0x4000000); $' . $result . '[$i] = (int) ($sum - ' . $class::BASE_FULL . ' * $upper);' :
|
||||
'$upper = $sum >> 31; $' . $result . '[$i] = $sum - ' . $class::BASE_FULL . ' * $upper;';
|
||||
$code .= '
|
||||
$' . $result . '[$j] = $upper;
|
||||
}
|
||||
if ($j == $length) {
|
||||
$sum = $' . $result . '[$i] + $_' . $y . '[$i] + $carry;
|
||||
$carry = $sum >= ' . self::float2string($class::BASE_FULL) . ';
|
||||
$' . $result . '[$i] = $carry ? $sum - ' . self::float2string($class::BASE_FULL) . ' : $sum;
|
||||
++$i;
|
||||
}
|
||||
if ($carry) {
|
||||
for (; $' . $result . '[$i] == ' . $class::MAX_DIGIT . '; ++$i) {
|
||||
$' . $result . '[$i] = 0;
|
||||
}
|
||||
++$' . $result . '[$i];
|
||||
}';
|
||||
$code .= self::generateInlineTrim($result);
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline Subtraction 2
|
||||
*
|
||||
* For when $known is more digits than $unknown. This is the harder use case to optimize for.
|
||||
*/
|
||||
private static function generateInlineSubtract2(string $known, string $unknown, string $result, string $class): string
|
||||
{
|
||||
$code = '
|
||||
$' . $result . ' = $' . $known . ';
|
||||
$carry = 0;
|
||||
$size = count($' . $unknown . ');
|
||||
for ($i = 0, $j = 1; $j < $size; $i+= 2, $j+= 2) {
|
||||
$sum = ($' . $known . '[$j] - $' . $unknown . '[$j]) * ' . $class::BASE_FULL . ' + $' . $known . '[$i]
|
||||
- $' . $unknown . '[$i]
|
||||
- $carry;
|
||||
$carry = $sum < 0;
|
||||
if ($carry) {
|
||||
$sum+= ' . self::float2string($class::MAX_DIGIT2) . ';
|
||||
}
|
||||
$subtemp = ';
|
||||
$code .= $class::BASE === 26 ?
|
||||
'intval($sum / 0x4000000);' :
|
||||
'$sum >> 31;';
|
||||
$code .= '$' . $result . '[$i] = ';
|
||||
if ($class::BASE === 26) {
|
||||
$code .= '(int) (';
|
||||
}
|
||||
$code .= '$sum - ' . $class::BASE_FULL . ' * $subtemp';
|
||||
if ($class::BASE === 26) {
|
||||
$code .= ')';
|
||||
}
|
||||
$code .= ';
|
||||
$' . $result . '[$j] = $subtemp;
|
||||
}
|
||||
if ($j == $size) {
|
||||
$sum = $' . $known . '[$i] - $' . $unknown . '[$i] - $carry;
|
||||
$carry = $sum < 0;
|
||||
$' . $result . '[$i] = $carry ? $sum + ' . $class::BASE_FULL . ' : $sum;
|
||||
++$i;
|
||||
}
|
||||
|
||||
if ($carry) {
|
||||
for (; !$' . $result . '[$i]; ++$i) {
|
||||
$' . $result . '[$i] = ' . $class::MAX_DIGIT . ';
|
||||
}
|
||||
--$' . $result . '[$i];
|
||||
}';
|
||||
|
||||
$code .= self::generateInlineTrim($result);
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline Subtraction 1
|
||||
*
|
||||
* For when $unknown is more digits than $known. This is the easier use case to optimize for.
|
||||
*/
|
||||
private static function generateInlineSubtract1(string $unknown, array $known, string $result, string $class): string
|
||||
{
|
||||
$code = '$' . $result . ' = $' . $unknown . ';';
|
||||
for ($i = 0, $j = 1; $j < count($known); $i += 2, $j += 2) {
|
||||
$code .= '$sum = $' . $unknown . '[' . $j . '] * ' . $class::BASE_FULL . ' + $' . $unknown . '[' . $i . '] - ';
|
||||
$code .= self::float2string($known[$j] * $class::BASE_FULL + $known[$i]);
|
||||
if ($i != 0) {
|
||||
$code .= ' - $carry';
|
||||
}
|
||||
|
||||
$code .= ';
|
||||
if ($carry = $sum < 0) {
|
||||
$sum+= ' . self::float2string($class::MAX_DIGIT2) . ';
|
||||
}
|
||||
$subtemp = ';
|
||||
$code .= $class::BASE === 26 ?
|
||||
'intval($sum / 0x4000000);' :
|
||||
'$sum >> 31;';
|
||||
$code .= '
|
||||
$' . $result . '[' . $i . '] = ';
|
||||
if ($class::BASE === 26) {
|
||||
$code .= ' (int) (';
|
||||
}
|
||||
$code .= '$sum - ' . $class::BASE_FULL . ' * $subtemp';
|
||||
if ($class::BASE === 26) {
|
||||
$code .= ')';
|
||||
}
|
||||
$code .= ';
|
||||
$' . $result . '[' . $j . '] = $subtemp;';
|
||||
}
|
||||
|
||||
$code .= '$i = ' . $i . ';';
|
||||
|
||||
if ($j == count($known)) {
|
||||
$code .= '
|
||||
$sum = $' . $unknown . '[' . $i . '] - ' . $known[$i] . ' - $carry;
|
||||
$carry = $sum < 0;
|
||||
$' . $result . '[' . $i . '] = $carry ? $sum + ' . $class::BASE_FULL . ' : $sum;
|
||||
++$i;';
|
||||
}
|
||||
|
||||
$code .= '
|
||||
if ($carry) {
|
||||
for (; !$' . $result . '[$i]; ++$i) {
|
||||
$' . $result . '[$i] = ' . $class::MAX_DIGIT . ';
|
||||
}
|
||||
--$' . $result . '[$i];
|
||||
}';
|
||||
$code .= self::generateInlineTrim($result);
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline Comparison
|
||||
*
|
||||
* If $unknown >= $known then loop
|
||||
*/
|
||||
private static function generateInlineCompare(array $known, string $unknown, string $subcode): string
|
||||
{
|
||||
$uniqid = uniqid();
|
||||
$code = 'loop_' . $uniqid . ':
|
||||
$clength = count($' . $unknown . ');
|
||||
switch (true) {
|
||||
case $clength < ' . count($known) . ':
|
||||
goto end_' . $uniqid . ';
|
||||
case $clength > ' . count($known) . ':';
|
||||
for ($i = count($known) - 1; $i >= 0; $i--) {
|
||||
$code .= '
|
||||
case $' . $unknown . '[' . $i . '] > ' . $known[$i] . ':
|
||||
goto subcode_' . $uniqid . ';
|
||||
case $' . $unknown . '[' . $i . '] < ' . $known[$i] . ':
|
||||
goto end_' . $uniqid . ';';
|
||||
}
|
||||
$code .= '
|
||||
default:
|
||||
// do subcode
|
||||
}
|
||||
|
||||
subcode_' . $uniqid . ':' . $subcode . '
|
||||
goto loop_' . $uniqid . ';
|
||||
|
||||
end_' . $uniqid . ':';
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a float to a string
|
||||
*
|
||||
* If you do echo floatval(pow(2, 52)) you'll get 4.6116860184274E+18. It /can/ be displayed without a loss of
|
||||
* precision but displayed in this way there will be precision loss, hence the need for this method.
|
||||
*
|
||||
* @param int|float $num
|
||||
*/
|
||||
private static function float2string($num): string
|
||||
{
|
||||
if (!is_float($num)) {
|
||||
return (string) $num;
|
||||
}
|
||||
|
||||
if ($num < 0) {
|
||||
return '-' . self::float2string(abs($num));
|
||||
}
|
||||
|
||||
$temp = '';
|
||||
while ($num) {
|
||||
$temp = fmod($num, 10) . $temp;
|
||||
$num = floor($num / 10);
|
||||
}
|
||||
|
||||
return $temp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Montgomery Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\PHP\Reductions;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\PHP\Montgomery as Progenitor;
|
||||
|
||||
/**
|
||||
* PHP Montgomery Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class Montgomery extends Progenitor
|
||||
{
|
||||
/**
|
||||
* Prepare a number for use in Montgomery Modular Reductions
|
||||
*/
|
||||
protected static function prepareReduce(array $x, array $n, string $class): array
|
||||
{
|
||||
$lhs = new $class();
|
||||
$lhs->value = array_merge(self::array_repeat(0, count($n)), $x);
|
||||
$rhs = new $class();
|
||||
$rhs->value = $n;
|
||||
|
||||
[, $temp] = $lhs->divide($rhs);
|
||||
return $temp->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Montgomery Multiply
|
||||
*
|
||||
* Interleaves the montgomery reduction and long multiplication algorithms together as described in
|
||||
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
|
||||
*/
|
||||
protected static function reduce(array $x, array $n, string $class): array
|
||||
{
|
||||
static $cache = [
|
||||
self::VARIABLE => [],
|
||||
self::DATA => [],
|
||||
];
|
||||
|
||||
if (($key = array_search($n, $cache[self::VARIABLE])) === false) {
|
||||
$key = count($cache[self::VARIABLE]);
|
||||
$cache[self::VARIABLE][] = $x;
|
||||
$cache[self::DATA][] = self::modInverse67108864($n, $class);
|
||||
}
|
||||
|
||||
$k = count($n);
|
||||
|
||||
$result = [self::VALUE => $x];
|
||||
|
||||
for ($i = 0; $i < $k; ++$i) {
|
||||
$temp = $result[self::VALUE][$i] * $cache[self::DATA][$key];
|
||||
$temp = $temp - $class::BASE_FULL * ($class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
|
||||
$temp = $class::regularMultiply([$temp], $n);
|
||||
$temp = array_merge(self::array_repeat(0, $i), $temp);
|
||||
$result = $class::addHelper($result[self::VALUE], false, $temp, false);
|
||||
}
|
||||
|
||||
$result[self::VALUE] = array_slice($result[self::VALUE], $k);
|
||||
|
||||
if (self::compareHelper($result, false, $n, false) >= 0) {
|
||||
$result = $class::subtractHelper($result[self::VALUE], false, $n, false);
|
||||
}
|
||||
|
||||
return $result[self::VALUE];
|
||||
}
|
||||
|
||||
/**
|
||||
* Modular Inverse of a number mod 2**26 (eg. 67108864)
|
||||
*
|
||||
* Based off of the bnpInvDigit function implemented and justified in the following URL:
|
||||
*
|
||||
* {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
|
||||
*
|
||||
* The following URL provides more info:
|
||||
*
|
||||
* {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
|
||||
*
|
||||
* As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For
|
||||
* instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
|
||||
* int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
|
||||
* auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that
|
||||
* the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the
|
||||
* maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to
|
||||
* 40 bits, which only 64-bit floating points will support.
|
||||
*
|
||||
* Thanks to Pedro Gimeno Fortea for input!
|
||||
*/
|
||||
protected static function modInverse67108864(array $x, string $class): int // 2**26 == 67,108,864
|
||||
{
|
||||
$x = -$x[0];
|
||||
$result = $x & 0x3; // x**-1 mod 2**2
|
||||
$result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
|
||||
$result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8
|
||||
$result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
|
||||
$result = $class::BASE == 26 ?
|
||||
fmod($result * (2 - fmod($x * $result, $class::BASE_FULL)), $class::BASE_FULL) : // x**-1 mod 2**26
|
||||
($result * (2 - ($x * $result) % $class::BASE_FULL)) % $class::BASE_FULL;
|
||||
return $result & $class::MAX_DIGIT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Montgomery Modular Exponentiation Engine with interleaved multiplication
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\PHP\Reductions;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\PHP;
|
||||
|
||||
/**
|
||||
* PHP Montgomery Modular Exponentiation Engine with interleaved multiplication
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class MontgomeryMult extends Montgomery
|
||||
{
|
||||
/**
|
||||
* Montgomery Multiply
|
||||
*
|
||||
* Interleaves the montgomery reduction and long multiplication algorithms together as described in
|
||||
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
|
||||
*
|
||||
* @param class-string<PHP> $class
|
||||
* @see self::_prepMontgomery()
|
||||
* @see self::_montgomery()
|
||||
*/
|
||||
public static function multiplyReduce(array $x, array $y, array $m, string $class): array
|
||||
{
|
||||
// the following code, although not callable, can be run independently of the above code
|
||||
// although the above code performed better in my benchmarks the following could might
|
||||
// perform better under different circumstances. in lieu of deleting it it's just been
|
||||
// made uncallable
|
||||
|
||||
static $cache = [
|
||||
self::VARIABLE => [],
|
||||
self::DATA => [],
|
||||
];
|
||||
|
||||
if (($key = array_search($m, $cache[self::VARIABLE])) === false) {
|
||||
$key = count($cache[self::VARIABLE]);
|
||||
$cache[self::VARIABLE][] = $m;
|
||||
$cache[self::DATA][] = self::modInverse67108864($m, $class);
|
||||
}
|
||||
|
||||
$n = max(count($x), count($y), count($m));
|
||||
$x = array_pad($x, $n, 0);
|
||||
$y = array_pad($y, $n, 0);
|
||||
$m = array_pad($m, $n, 0);
|
||||
$a = [self::VALUE => self::array_repeat(0, $n + 1)];
|
||||
for ($i = 0; $i < $n; ++$i) {
|
||||
$temp = $a[self::VALUE][0] + $x[$i] * $y[0];
|
||||
$temp = $temp - $class::BASE_FULL * ($class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
|
||||
$temp = $temp * $cache[self::DATA][$key];
|
||||
$temp = $temp - $class::BASE_FULL * ($class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
|
||||
$temp = $class::addHelper($class::regularMultiply([$x[$i]], $y), false, $class::regularMultiply([$temp], $m), false);
|
||||
$a = $class::addHelper($a[self::VALUE], false, $temp[self::VALUE], false);
|
||||
$a[self::VALUE] = array_slice($a[self::VALUE], 1);
|
||||
}
|
||||
if (self::compareHelper($a[self::VALUE], false, $m, false) >= 0) {
|
||||
$a = $class::subtractHelper($a[self::VALUE], false, $m, false);
|
||||
}
|
||||
return $a[self::VALUE];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHP Power of Two Modular Exponentiation Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines\PHP\Reductions;
|
||||
|
||||
use phpseclib3\Math\BigInteger\Engines\PHP\Base;
|
||||
|
||||
/**
|
||||
* PHP Power Of Two Modular Exponentiation Engine
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class PowerOfTwo extends Base
|
||||
{
|
||||
/**
|
||||
* Prepare a number for use in Montgomery Modular Reductions
|
||||
*/
|
||||
protected static function prepareReduce(array $x, array $n, string $class): array
|
||||
{
|
||||
return self::reduce($x, $n, $class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Power Of Two Reduction
|
||||
*/
|
||||
protected static function reduce(array $x, array $n, string $class): array
|
||||
{
|
||||
$lhs = new $class();
|
||||
$lhs->value = $x;
|
||||
$rhs = new $class();
|
||||
$rhs->value = $n;
|
||||
|
||||
$temp = new $class();
|
||||
$temp->value = [1];
|
||||
|
||||
$result = $lhs->bitwise_and($rhs->subtract($temp));
|
||||
return $result->value;
|
||||
}
|
||||
}
|
||||
317
qa-tool/htdocs/oidc/phpseclib/Math/BigInteger/Engines/PHP32.php
Normal file
317
qa-tool/htdocs/oidc/phpseclib/Math/BigInteger/Engines/PHP32.php
Normal file
@@ -0,0 +1,317 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Pure-PHP 32-bit BigInteger Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines;
|
||||
|
||||
/**
|
||||
* Pure-PHP 32-bit Engine.
|
||||
*
|
||||
* Uses 64-bit floats if int size is 4 bits
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class PHP32 extends PHP
|
||||
{
|
||||
// Constants used by PHP.php
|
||||
public const BASE = 26;
|
||||
public const BASE_FULL = 0x4000000;
|
||||
public const MAX_DIGIT = 0x3FFFFFF;
|
||||
public const MSB = 0x2000000;
|
||||
|
||||
/**
|
||||
* MAX10 in greatest MAX10LEN satisfying
|
||||
* MAX10 = 10**MAX10LEN <= 2**BASE.
|
||||
*/
|
||||
public const MAX10 = 10000000;
|
||||
|
||||
/**
|
||||
* MAX10LEN in greatest MAX10LEN satisfying
|
||||
* MAX10 = 10**MAX10LEN <= 2**BASE.
|
||||
*/
|
||||
public const MAX10LEN = 7;
|
||||
public const MAX_DIGIT2 = 4503599627370496;
|
||||
|
||||
/**
|
||||
* Initialize a PHP32 BigInteger Engine instance
|
||||
*
|
||||
* @see parent::initialize()
|
||||
*/
|
||||
protected function initialize(int $base): void
|
||||
{
|
||||
if ($base != 256 && $base != -256) {
|
||||
parent::initialize($base);
|
||||
return;
|
||||
}
|
||||
|
||||
$val = $this->value;
|
||||
$this->value = [];
|
||||
$vals = &$this->value;
|
||||
$i = strlen($val);
|
||||
if (!$i) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
$i -= 4;
|
||||
if ($i < 0) {
|
||||
if ($i == -4) {
|
||||
break;
|
||||
}
|
||||
$val = substr($val, 0, 4 + $i);
|
||||
$val = str_pad($val, 4, "\0", STR_PAD_LEFT);
|
||||
if ($val == "\0\0\0\0") {
|
||||
break;
|
||||
}
|
||||
$i = 0;
|
||||
}
|
||||
[, $digit] = unpack('N', substr($val, $i, 4));
|
||||
if ($digit < 0) {
|
||||
$digit += 0xFFFFFFFF + 1;
|
||||
}
|
||||
$step = count($vals) & 3;
|
||||
if ($step) {
|
||||
$digit = (int) floor($digit / 2 ** (2 * $step));
|
||||
}
|
||||
if ($step != 3) {
|
||||
$digit = (int) fmod($digit, static::BASE_FULL);
|
||||
$i++;
|
||||
}
|
||||
$vals[] = $digit;
|
||||
}
|
||||
while (end($vals) === 0) {
|
||||
array_pop($vals);
|
||||
}
|
||||
reset($vals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for engine validity
|
||||
*
|
||||
* @see parent::__construct()
|
||||
*/
|
||||
public static function isValidEngine(): bool
|
||||
{
|
||||
return PHP_INT_SIZE >= 4 && !self::testJITOnWindows();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two BigIntegers.
|
||||
*/
|
||||
public function add(PHP32 $y): PHP32
|
||||
{
|
||||
$temp = self::addHelper($this->value, $this->is_negative, $y->value, $y->is_negative);
|
||||
|
||||
return $this->convertToObj($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts two BigIntegers.
|
||||
*/
|
||||
public function subtract(PHP32 $y): PHP32
|
||||
{
|
||||
$temp = self::subtractHelper($this->value, $this->is_negative, $y->value, $y->is_negative);
|
||||
|
||||
return $this->convertToObj($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two BigIntegers.
|
||||
*/
|
||||
public function multiply(PHP32 $y): PHP32
|
||||
{
|
||||
$temp = self::multiplyHelper($this->value, $this->is_negative, $y->value, $y->is_negative);
|
||||
|
||||
return $this->convertToObj($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (basically, the "common residue" is the first positive modulo).
|
||||
*
|
||||
* @return array{PHP32, PHP32}
|
||||
*/
|
||||
public function divide(PHP32 $y): array
|
||||
{
|
||||
return $this->divideHelper($y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates modular inverses.
|
||||
*
|
||||
* Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
|
||||
* @return false|PHP32
|
||||
*/
|
||||
public function modInverse(PHP32 $n)
|
||||
{
|
||||
return $this->modInverseHelper($n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates modular inverses.
|
||||
*
|
||||
* Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
|
||||
* @return PHP32[]
|
||||
*/
|
||||
public function extendedGCD(PHP32 $n): array
|
||||
{
|
||||
return $this->extendedGCDHelper($n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the greatest common divisor
|
||||
*
|
||||
* Say you have 693 and 609. The GCD is 21.
|
||||
*/
|
||||
public function gcd(PHP32 $n): PHP32
|
||||
{
|
||||
return $this->extendedGCD($n)['gcd'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical And
|
||||
*/
|
||||
public function bitwise_and(PHP32 $x): PHP32
|
||||
{
|
||||
return $this->bitwiseAndHelper($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Or
|
||||
*/
|
||||
public function bitwise_or(PHP32 $x): PHP32
|
||||
{
|
||||
return $this->bitwiseOrHelper($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Exclusive Or
|
||||
*/
|
||||
public function bitwise_xor(PHP32 $x): PHP32
|
||||
{
|
||||
return $this->bitwiseXorHelper($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two numbers.
|
||||
*
|
||||
* Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is
|
||||
* demonstrated thusly:
|
||||
*
|
||||
* $x > $y: $x->compare($y) > 0
|
||||
* $x < $y: $x->compare($y) < 0
|
||||
* $x == $y: $x->compare($y) == 0
|
||||
*
|
||||
* Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
|
||||
*
|
||||
* {@internal Could return $this->subtract($x), but that's not as fast as what we do do.}
|
||||
*
|
||||
* @return int in case < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
|
||||
* @see self::equals()
|
||||
*/
|
||||
public function compare(PHP32 $y): int
|
||||
{
|
||||
return $this->compareHelper($this->value, $this->is_negative, $y->value, $y->is_negative);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the equality of two numbers.
|
||||
*
|
||||
* If you need to see if one number is greater than or less than another number, use BigInteger::compare()
|
||||
*/
|
||||
public function equals(PHP32 $x): bool
|
||||
{
|
||||
return $this->value === $x->value && $this->is_negative == $x->is_negative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*/
|
||||
public function modPow(PHP32 $e, PHP32 $n): PHP32
|
||||
{
|
||||
return $this->powModOuter($e, $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*
|
||||
* Alias for modPow().
|
||||
*/
|
||||
public function powMod(PHP32 $e, PHP32 $n): PHP32
|
||||
{
|
||||
return $this->powModOuter($e, $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random prime number between a range
|
||||
*
|
||||
* If there's not a prime within the given range, false will be returned.
|
||||
*
|
||||
* @return false|PHP32
|
||||
*/
|
||||
public static function randomRangePrime(PHP32 $min, PHP32 $max)
|
||||
{
|
||||
return self::randomRangePrimeOuter($min, $max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random number between a range
|
||||
*
|
||||
* Returns a random number between $min and $max where $min and $max
|
||||
* can be defined using one of the two methods:
|
||||
*
|
||||
* BigInteger::randomRange($min, $max)
|
||||
* BigInteger::randomRange($max, $min)
|
||||
*/
|
||||
public static function randomRange(PHP32 $min, PHP32 $max): PHP32
|
||||
{
|
||||
return self::randomRangeHelper($min, $max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs exponentiation.
|
||||
*/
|
||||
public function pow(PHP32 $n): PHP32
|
||||
{
|
||||
return $this->powHelper($n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum BigInteger between an arbitrary number of BigIntegers.
|
||||
*/
|
||||
public static function min(PHP32 ...$nums): PHP32
|
||||
{
|
||||
return self::minHelper($nums);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum BigInteger between an arbitrary number of BigIntegers.
|
||||
*/
|
||||
public static function max(PHP32 ...$nums): PHP32
|
||||
{
|
||||
return self::maxHelper($nums);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests BigInteger to see if it is between two integers, inclusive
|
||||
*/
|
||||
public function between(PHP32 $min, PHP32 $max): bool
|
||||
{
|
||||
return $this->compare($min) >= 0 && $this->compare($max) <= 0;
|
||||
}
|
||||
}
|
||||
320
qa-tool/htdocs/oidc/phpseclib/Math/BigInteger/Engines/PHP64.php
Normal file
320
qa-tool/htdocs/oidc/phpseclib/Math/BigInteger/Engines/PHP64.php
Normal file
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Pure-PHP 64-bit BigInteger Engine
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BigInteger\Engines;
|
||||
|
||||
/**
|
||||
* Pure-PHP 64-bit Engine.
|
||||
*
|
||||
* Uses 64-bit integers if int size is 8 bits
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class PHP64 extends PHP
|
||||
{
|
||||
// Constants used by PHP.php
|
||||
public const BASE = 31;
|
||||
public const BASE_FULL = 0x80000000;
|
||||
public const MAX_DIGIT = 0x7FFFFFFF;
|
||||
public const MSB = 0x40000000;
|
||||
|
||||
/**
|
||||
* MAX10 in greatest MAX10LEN satisfying
|
||||
* MAX10 = 10**MAX10LEN <= 2**BASE.
|
||||
*/
|
||||
public const MAX10 = 1000000000;
|
||||
|
||||
/**
|
||||
* MAX10LEN in greatest MAX10LEN satisfying
|
||||
* MAX10 = 10**MAX10LEN <= 2**BASE.
|
||||
*/
|
||||
public const MAX10LEN = 9;
|
||||
public const MAX_DIGIT2 = 4611686018427387904;
|
||||
|
||||
/**
|
||||
* Initialize a PHP64 BigInteger Engine instance
|
||||
*
|
||||
* @see parent::initialize()
|
||||
*/
|
||||
protected function initialize(int $base): void
|
||||
{
|
||||
if ($base != 256 && $base != -256) {
|
||||
parent::initialize($base);
|
||||
return;
|
||||
}
|
||||
|
||||
$val = $this->value;
|
||||
$this->value = [];
|
||||
$vals = &$this->value;
|
||||
$i = strlen($val);
|
||||
if (!$i) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
$i -= 4;
|
||||
if ($i < 0) {
|
||||
if ($i == -4) {
|
||||
break;
|
||||
}
|
||||
$val = substr($val, 0, 4 + $i);
|
||||
$val = str_pad($val, 4, "\0", STR_PAD_LEFT);
|
||||
if ($val == "\0\0\0\0") {
|
||||
break;
|
||||
}
|
||||
$i = 0;
|
||||
}
|
||||
[, $digit] = unpack('N', substr($val, $i, 4));
|
||||
$step = count($vals) & 7;
|
||||
if (!$step) {
|
||||
$digit &= static::MAX_DIGIT;
|
||||
$i++;
|
||||
} else {
|
||||
$shift = 8 - $step;
|
||||
$digit >>= $shift;
|
||||
$shift = 32 - $shift;
|
||||
$digit &= (1 << $shift) - 1;
|
||||
$temp = $i > 0 ? ord($val[$i - 1]) : 0;
|
||||
$digit |= ($temp << $shift) & 0x7F000000;
|
||||
}
|
||||
$vals[] = $digit;
|
||||
}
|
||||
while (end($vals) === 0) {
|
||||
array_pop($vals);
|
||||
}
|
||||
reset($vals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for engine validity
|
||||
*
|
||||
* @see parent::__construct()
|
||||
*/
|
||||
public static function isValidEngine(): bool
|
||||
{
|
||||
return PHP_INT_SIZE >= 8 && !self::testJITOnWindows();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two BigIntegers.
|
||||
*/
|
||||
public function add(PHP64 $y): PHP64
|
||||
{
|
||||
$temp = self::addHelper($this->value, $this->is_negative, $y->value, $y->is_negative);
|
||||
|
||||
return $this->convertToObj($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts two BigIntegers.
|
||||
*/
|
||||
public function subtract(PHP64 $y): PHP64
|
||||
{
|
||||
$temp = self::subtractHelper($this->value, $this->is_negative, $y->value, $y->is_negative);
|
||||
|
||||
return $this->convertToObj($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two BigIntegers.
|
||||
*/
|
||||
public function multiply(PHP64 $y): PHP64
|
||||
{
|
||||
$temp = self::multiplyHelper($this->value, $this->is_negative, $y->value, $y->is_negative);
|
||||
|
||||
return $this->convertToObj($temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (basically, the "common residue" is the first positive modulo).
|
||||
*
|
||||
* @return array{PHP64, PHP64}
|
||||
*/
|
||||
public function divide(PHP64 $y): array
|
||||
{
|
||||
return $this->divideHelper($y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates modular inverses.
|
||||
*
|
||||
* Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
|
||||
* @return false|PHP64
|
||||
*/
|
||||
public function modInverse(PHP64 $n)
|
||||
{
|
||||
return $this->modInverseHelper($n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates modular inverses.
|
||||
*
|
||||
* Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
|
||||
* @return PHP64[]
|
||||
*/
|
||||
public function extendedGCD(PHP64 $n): array
|
||||
{
|
||||
return $this->extendedGCDHelper($n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the greatest common divisor
|
||||
*
|
||||
* Say you have 693 and 609. The GCD is 21.
|
||||
*/
|
||||
public function gcd(PHP64 $n): PHP64
|
||||
{
|
||||
return $this->extendedGCD($n)['gcd'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical And
|
||||
*/
|
||||
public function bitwise_and(PHP64 $x): PHP64
|
||||
{
|
||||
return $this->bitwiseAndHelper($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Or
|
||||
*/
|
||||
public function bitwise_or(PHP64 $x): PHP64
|
||||
{
|
||||
return $this->bitwiseOrHelper($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical Exclusive Or
|
||||
*/
|
||||
public function bitwise_xor(PHP64 $x): PHP64
|
||||
{
|
||||
return $this->bitwiseXorHelper($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two numbers.
|
||||
*
|
||||
* Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is
|
||||
* demonstrated thusly:
|
||||
*
|
||||
* $x > $y: $x->compare($y) > 0
|
||||
* $x < $y: $x->compare($y) < 0
|
||||
* $x == $y: $x->compare($y) == 0
|
||||
*
|
||||
* Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
|
||||
*
|
||||
* {@internal Could return $this->subtract($x), but that's not as fast as what we do do.}
|
||||
*
|
||||
* @return int in case < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
|
||||
* @see self::equals()
|
||||
*/
|
||||
public function compare(PHP64 $y): int
|
||||
{
|
||||
return parent::compareHelper($this->value, $this->is_negative, $y->value, $y->is_negative);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the equality of two numbers.
|
||||
*
|
||||
* If you need to see if one number is greater than or less than another number, use BigInteger::compare()
|
||||
*/
|
||||
public function equals(PHP64 $x): bool
|
||||
{
|
||||
return $this->value === $x->value && $this->is_negative == $x->is_negative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*/
|
||||
public function modPow(PHP64 $e, PHP64 $n): PHP64
|
||||
{
|
||||
return $this->powModOuter($e, $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*
|
||||
* Alias for modPow().
|
||||
*
|
||||
* @return PHP64|false
|
||||
*/
|
||||
public function powMod(PHP64 $e, PHP64 $n)
|
||||
{
|
||||
return $this->powModOuter($e, $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random prime number between a range
|
||||
*
|
||||
* If there's not a prime within the given range, false will be returned.
|
||||
*
|
||||
* @return false|PHP64
|
||||
*/
|
||||
public static function randomRangePrime(PHP64 $min, PHP64 $max)
|
||||
{
|
||||
return self::randomRangePrimeOuter($min, $max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random number between a range
|
||||
*
|
||||
* Returns a random number between $min and $max where $min and $max
|
||||
* can be defined using one of the two methods:
|
||||
*
|
||||
* BigInteger::randomRange($min, $max)
|
||||
* BigInteger::randomRange($max, $min)
|
||||
*/
|
||||
public static function randomRange(PHP64 $min, PHP64 $max): PHP64
|
||||
{
|
||||
return self::randomRangeHelper($min, $max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs exponentiation.
|
||||
*/
|
||||
public function pow(PHP64 $n): PHP64
|
||||
{
|
||||
return $this->powHelper($n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum BigInteger between an arbitrary number of BigIntegers.
|
||||
*/
|
||||
public static function min(PHP64 ...$nums): PHP64
|
||||
{
|
||||
return self::minHelper($nums);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum BigInteger between an arbitrary number of BigIntegers.
|
||||
*/
|
||||
public static function max(PHP64 ...$nums): PHP64
|
||||
{
|
||||
return self::maxHelper($nums);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests BigInteger to see if it is between two integers, inclusive
|
||||
*/
|
||||
public function between(PHP64 $min, PHP64 $max): bool
|
||||
{
|
||||
return $this->compare($min) >= 0 && $this->compare($max) <= 0;
|
||||
}
|
||||
}
|
||||
192
qa-tool/htdocs/oidc/phpseclib/Math/BinaryField.php
Normal file
192
qa-tool/htdocs/oidc/phpseclib/Math/BinaryField.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Binary Finite Fields
|
||||
*
|
||||
* Utilizes the factory design pattern
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math;
|
||||
|
||||
use phpseclib3\Common\Functions\Strings;
|
||||
use phpseclib3\Exception\OutOfBoundsException;
|
||||
use phpseclib3\Math\BinaryField\Integer;
|
||||
use phpseclib3\Math\Common\FiniteField;
|
||||
|
||||
/**
|
||||
* Binary Finite Fields
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class BinaryField extends FiniteField
|
||||
{
|
||||
/**
|
||||
* Instance Counter
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $instanceCounter = 0;
|
||||
|
||||
/**
|
||||
* Keeps track of current instance
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $instanceID;
|
||||
|
||||
/** @var BigInteger */
|
||||
private $randomMax;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public function __construct(...$indices)
|
||||
{
|
||||
$m = array_shift($indices);
|
||||
if ($m > 571) {
|
||||
/* sect571r1 and sect571k1 are the largest binary curves that https://www.secg.org/sec2-v2.pdf defines
|
||||
altho theoretically there may be legit reasons to use binary finite fields with larger degrees
|
||||
imposing a limit on the maximum size is both reasonable and precedented. in particular,
|
||||
http://tools.ietf.org/html/rfc4253#section-6.1 (The Secure Shell (SSH) Transport Layer Protocol) says
|
||||
"implementations SHOULD check that the packet length is reasonable in order for the implementation to
|
||||
avoid denial of service and/or buffer overflow attacks" */
|
||||
throw new OutOfBoundsException('Degrees larger than 571 are not supported');
|
||||
}
|
||||
$val = str_repeat('0', $m) . '1';
|
||||
foreach ($indices as $index) {
|
||||
$val[$index] = '1';
|
||||
}
|
||||
$modulo = static::base2ToBase256(strrev($val));
|
||||
|
||||
$mStart = 2 * $m - 2;
|
||||
$t = (int) ceil($m / 8);
|
||||
$finalMask = chr((1 << ($m % 8)) - 1);
|
||||
if ($finalMask == "\0") {
|
||||
$finalMask = "\xFF";
|
||||
}
|
||||
$bitLen = $mStart + 1;
|
||||
$pad = (int) ceil($bitLen / 8);
|
||||
$h = $bitLen & 7;
|
||||
$h = $h ? 8 - $h : 0;
|
||||
|
||||
$r = rtrim(substr($val, 0, -1), '0');
|
||||
$u = [static::base2ToBase256(strrev($r))];
|
||||
for ($i = 1; $i < 8; $i++) {
|
||||
$u[] = static::base2ToBase256(strrev(str_repeat('0', $i) . $r));
|
||||
}
|
||||
|
||||
// implements algorithm 2.40 (in section 2.3.5) in "Guide to Elliptic Curve Cryptography"
|
||||
// with W = 8
|
||||
$reduce = function ($c) use ($u, $mStart, $m, $t, $finalMask, $pad, $h) {
|
||||
$c = str_pad($c, $pad, "\0", STR_PAD_LEFT);
|
||||
for ($i = $mStart; $i >= $m;) {
|
||||
$g = $h >> 3;
|
||||
$mask = $h & 7;
|
||||
$mask = $mask ? 1 << (7 - $mask) : 0x80;
|
||||
for (; $mask > 0; $mask >>= 1, $i--, $h++) {
|
||||
if (ord($c[$g]) & $mask) {
|
||||
$temp = $i - $m;
|
||||
$j = $temp >> 3;
|
||||
$k = $temp & 7;
|
||||
$t1 = $j ? substr($c, 0, -$j) : $c;
|
||||
$length = strlen($t1);
|
||||
if ($length) {
|
||||
$t2 = str_pad($u[$k], $length, "\0", STR_PAD_LEFT);
|
||||
$temp = $t1 ^ $t2;
|
||||
$c = $j ? substr_replace($c, $temp, 0, $length) : $temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$c = substr($c, -$t);
|
||||
if (strlen($c) == $t) {
|
||||
$c[0] = $c[0] & $finalMask;
|
||||
}
|
||||
return ltrim($c, "\0");
|
||||
};
|
||||
|
||||
$this->instanceID = self::$instanceCounter++;
|
||||
Integer::setModulo($this->instanceID, $modulo);
|
||||
Integer::setRecurringModuloFunction($this->instanceID, $reduce);
|
||||
|
||||
$this->randomMax = new BigInteger($modulo, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of a dynamically generated PrimeFieldInteger class
|
||||
*
|
||||
* @param BigInteger|string $num
|
||||
*/
|
||||
public function newInteger($num): Integer
|
||||
{
|
||||
return new Integer($this->instanceID, $num instanceof BigInteger ? $num->toBytes() : $num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an integer on the finite field between one and the prime modulo
|
||||
*/
|
||||
public function randomInteger(): Integer
|
||||
{
|
||||
static $one;
|
||||
if (!isset($one)) {
|
||||
$one = new BigInteger(1);
|
||||
}
|
||||
|
||||
return new Integer($this->instanceID, BigInteger::randomRange($one, $this->randomMax)->toBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the modulo in bytes
|
||||
*/
|
||||
public function getLengthInBytes(): int
|
||||
{
|
||||
return strlen(Integer::getModulo($this->instanceID));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the modulo in bits
|
||||
*/
|
||||
public function getLength(): int
|
||||
{
|
||||
return strlen(Integer::getModulo($this->instanceID)) << 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a base-2 string to a base-256 string
|
||||
*/
|
||||
public static function base2ToBase256(string $x, ?int $size = null): string
|
||||
{
|
||||
$str = Strings::bits2bin($x);
|
||||
|
||||
$pad = strlen($x) >> 3;
|
||||
if (strlen($x) & 3) {
|
||||
$pad++;
|
||||
}
|
||||
$str = str_pad($str, $pad, "\0", STR_PAD_LEFT);
|
||||
if (isset($size)) {
|
||||
$str = str_pad($str, $size, "\0", STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a base-256 string to a base-2 string
|
||||
*/
|
||||
public static function base256ToBase2(string $x): string
|
||||
{
|
||||
if (function_exists('gmp_import')) {
|
||||
return gmp_strval(gmp_import($x), 2);
|
||||
}
|
||||
|
||||
return Strings::bin2bits($x);
|
||||
}
|
||||
}
|
||||
489
qa-tool/htdocs/oidc/phpseclib/Math/BinaryField/Integer.php
Normal file
489
qa-tool/htdocs/oidc/phpseclib/Math/BinaryField/Integer.php
Normal file
@@ -0,0 +1,489 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Binary Finite Fields
|
||||
*
|
||||
* In a binary finite field numbers are actually polynomial equations. If you
|
||||
* represent the number as a sequence of bits you get a sequence of 1's or 0's.
|
||||
* These 1's or 0's represent the coefficients of the x**n, where n is the
|
||||
* location of the given bit. When you add numbers over a binary finite field
|
||||
* the result should have a coefficient of 1 or 0 as well. Hence addition
|
||||
* and subtraction become the same operation as XOR.
|
||||
* eg. 1 + 1 + 1 == 3 % 2 == 1 or 0 - 1 == -1 % 2 == 1
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math\BinaryField;
|
||||
|
||||
use phpseclib3\Common\Functions\Strings;
|
||||
use phpseclib3\Exception\UnexpectedValueException;
|
||||
use phpseclib3\Math\BigInteger;
|
||||
use phpseclib3\Math\BinaryField;
|
||||
use phpseclib3\Math\Common\FiniteField\Integer as Base;
|
||||
|
||||
/**
|
||||
* Binary Finite Fields
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class Integer extends Base
|
||||
{
|
||||
/**
|
||||
* Holds the BinaryField's value
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* Keeps track of current instance
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $instanceID;
|
||||
|
||||
/**
|
||||
* Holds the PrimeField's modulo
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected static $modulo;
|
||||
|
||||
/**
|
||||
* Holds a pre-generated function to perform modulo reductions
|
||||
*
|
||||
* @var callable[]
|
||||
*/
|
||||
protected static $reduce;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public function __construct($instanceID, $num = '')
|
||||
{
|
||||
$this->instanceID = $instanceID;
|
||||
if (!strlen($num)) {
|
||||
$this->value = '';
|
||||
} else {
|
||||
$reduce = static::$reduce[$instanceID];
|
||||
$this->value = $reduce($num);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the modulo for a given instance
|
||||
*/
|
||||
public static function setModulo(int $instanceID, string $modulo): void
|
||||
{
|
||||
static::$modulo[$instanceID] = $modulo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the modulo for a given instance
|
||||
*/
|
||||
public static function setRecurringModuloFunction($instanceID, callable $function): void
|
||||
{
|
||||
static::$reduce[$instanceID] = $function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a parameter to see if it's of the right instance
|
||||
*
|
||||
* Throws an exception if the incorrect class is being utilized
|
||||
*/
|
||||
private static function checkInstance(self $x, self $y): void
|
||||
{
|
||||
if ($x->instanceID != $y->instanceID) {
|
||||
throw new UnexpectedValueException('The instances of the two BinaryField\Integer objects do not match');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the equality of two numbers.
|
||||
*/
|
||||
public function equals(self $x): bool
|
||||
{
|
||||
static::checkInstance($this, $x);
|
||||
|
||||
return $this->value == $x->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two numbers.
|
||||
*/
|
||||
public function compare(self $x): int
|
||||
{
|
||||
static::checkInstance($this, $x);
|
||||
|
||||
$a = $this->value;
|
||||
$b = $x->value;
|
||||
|
||||
$length = max(strlen($a), strlen($b));
|
||||
|
||||
$a = str_pad($a, $length, "\0", STR_PAD_LEFT);
|
||||
$b = str_pad($b, $length, "\0", STR_PAD_LEFT);
|
||||
|
||||
return strcmp($a, $b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the degree of the polynomial
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private static function deg(string $x)
|
||||
{
|
||||
$x = ltrim($x, "\0");
|
||||
$xbit = decbin(ord($x[0]));
|
||||
$xlen = $xbit == '0' ? 0 : strlen($xbit);
|
||||
$len = strlen($x);
|
||||
if (!$len) {
|
||||
return -1;
|
||||
}
|
||||
return 8 * strlen($x) - 9 + $xlen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform polynomial division
|
||||
*
|
||||
* @return string[]
|
||||
* @link https://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor#Euclidean_division
|
||||
*/
|
||||
private static function polynomialDivide(string $x, string $y): array
|
||||
{
|
||||
// in wikipedia's description of the algorithm, lc() is the leading coefficient. over a binary field that's
|
||||
// always going to be 1.
|
||||
|
||||
$q = chr(0);
|
||||
$d = static::deg($y);
|
||||
$r = $x;
|
||||
while (($degr = static::deg($r)) >= $d) {
|
||||
$s = '1' . str_repeat('0', $degr - $d);
|
||||
$s = BinaryField::base2ToBase256($s);
|
||||
$length = max(strlen($s), strlen($q));
|
||||
$q = !isset($q) ? $s :
|
||||
str_pad($q, $length, "\0", STR_PAD_LEFT) ^
|
||||
str_pad($s, $length, "\0", STR_PAD_LEFT);
|
||||
$s = static::polynomialMultiply($s, $y);
|
||||
$length = max(strlen($r), strlen($s));
|
||||
$r = str_pad($r, $length, "\0", STR_PAD_LEFT) ^
|
||||
str_pad($s, $length, "\0", STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
return [ltrim($q, "\0"), ltrim($r, "\0")];
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform polynomial multiplation in the traditional way
|
||||
*
|
||||
* @link https://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplication
|
||||
*/
|
||||
private static function regularPolynomialMultiply(string $x, string $y): string
|
||||
{
|
||||
$precomputed = [ltrim($x, "\0")];
|
||||
$x = strrev(BinaryField::base256ToBase2($x));
|
||||
$y = strrev(BinaryField::base256ToBase2($y));
|
||||
if (strlen($x) == strlen($y)) {
|
||||
$length = strlen($x);
|
||||
} else {
|
||||
$length = max(strlen($x), strlen($y));
|
||||
$x = str_pad($x, $length, '0');
|
||||
$y = str_pad($y, $length, '0');
|
||||
}
|
||||
$result = str_repeat('0', 2 * $length - 1);
|
||||
$result = BinaryField::base2ToBase256($result);
|
||||
$size = strlen($result);
|
||||
$x = strrev($x);
|
||||
|
||||
// precompute left shift 1 through 7
|
||||
for ($i = 1; $i < 8; $i++) {
|
||||
$precomputed[$i] = BinaryField::base2ToBase256($x . str_repeat('0', $i));
|
||||
}
|
||||
for ($i = 0; $i < strlen($y); $i++) {
|
||||
if ($y[$i] == '1') {
|
||||
$temp = $precomputed[$i & 7] . str_repeat("\0", $i >> 3);
|
||||
$result ^= str_pad($temp, $size, "\0", STR_PAD_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform polynomial multiplation
|
||||
*
|
||||
* Uses karatsuba multiplication to reduce x-bit multiplications to a series of 32-bit multiplications
|
||||
*
|
||||
* @link https://en.wikipedia.org/wiki/Karatsuba_algorithm
|
||||
*/
|
||||
private static function polynomialMultiply(string $x, string $y): string
|
||||
{
|
||||
if (strlen($x) == strlen($y)) {
|
||||
$length = strlen($x);
|
||||
} else {
|
||||
$length = max(strlen($x), strlen($y));
|
||||
$x = str_pad($x, $length, "\0", STR_PAD_LEFT);
|
||||
$y = str_pad($y, $length, "\0", STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case PHP_INT_SIZE == 8 && $length <= 4:
|
||||
return $length != 4 ?
|
||||
self::subMultiply(str_pad($x, 4, "\0", STR_PAD_LEFT), str_pad($y, 4, "\0", STR_PAD_LEFT)) :
|
||||
self::subMultiply($x, $y);
|
||||
case PHP_INT_SIZE == 4 || $length > 32:
|
||||
return self::regularPolynomialMultiply($x, $y);
|
||||
}
|
||||
|
||||
$m = $length >> 1;
|
||||
|
||||
$x1 = substr($x, 0, -$m);
|
||||
$x0 = substr($x, -$m);
|
||||
$y1 = substr($y, 0, -$m);
|
||||
$y0 = substr($y, -$m);
|
||||
|
||||
$z2 = self::polynomialMultiply($x1, $y1);
|
||||
$z0 = self::polynomialMultiply($x0, $y0);
|
||||
$z1 = self::polynomialMultiply(
|
||||
self::subAdd2($x1, $x0),
|
||||
self::subAdd2($y1, $y0)
|
||||
);
|
||||
|
||||
$z1 = self::subAdd3($z1, $z2, $z0);
|
||||
|
||||
$xy = self::subAdd3(
|
||||
$z2 . str_repeat("\0", 2 * $m),
|
||||
$z1 . str_repeat("\0", $m),
|
||||
$z0
|
||||
);
|
||||
|
||||
return ltrim($xy, "\0");
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform polynomial multiplication on 2x 32-bit numbers, returning
|
||||
* a 64-bit number
|
||||
*
|
||||
* @link https://www.bearssl.org/constanttime.html#ghash-for-gcm
|
||||
*/
|
||||
private static function subMultiply(string $x, string $y): string
|
||||
{
|
||||
$x = unpack('N', $x)[1];
|
||||
$y = unpack('N', $y)[1];
|
||||
|
||||
$x0 = $x & 0x11111111;
|
||||
$x1 = $x & 0x22222222;
|
||||
$x2 = $x & 0x44444444;
|
||||
$x3 = $x & 0x88888888;
|
||||
|
||||
$y0 = $y & 0x11111111;
|
||||
$y1 = $y & 0x22222222;
|
||||
$y2 = $y & 0x44444444;
|
||||
$y3 = $y & 0x88888888;
|
||||
|
||||
$z0 = ($x0 * $y0) ^ ($x1 * $y3) ^ ($x2 * $y2) ^ ($x3 * $y1);
|
||||
$z1 = ($x0 * $y1) ^ ($x1 * $y0) ^ ($x2 * $y3) ^ ($x3 * $y2);
|
||||
$z2 = ($x0 * $y2) ^ ($x1 * $y1) ^ ($x2 * $y0) ^ ($x3 * $y3);
|
||||
$z3 = ($x0 * $y3) ^ ($x1 * $y2) ^ ($x2 * $y1) ^ ($x3 * $y0);
|
||||
|
||||
$z0 &= 0x1111111111111111;
|
||||
$z1 &= 0x2222222222222222;
|
||||
$z2 &= 0x4444444444444444;
|
||||
$z3 &= -8608480567731124088; // 0x8888888888888888 gets interpreted as a float
|
||||
|
||||
$z = $z0 | $z1 | $z2 | $z3;
|
||||
|
||||
return pack('J', $z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two numbers
|
||||
*/
|
||||
private static function subAdd2(string $x, string $y): string
|
||||
{
|
||||
$length = max(strlen($x), strlen($y));
|
||||
$x = str_pad($x, $length, "\0", STR_PAD_LEFT);
|
||||
$y = str_pad($y, $length, "\0", STR_PAD_LEFT);
|
||||
return $x ^ $y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds three numbers
|
||||
*/
|
||||
private static function subAdd3(string $x, string $y, $z): string
|
||||
{
|
||||
$length = max(strlen($x), strlen($y), strlen($z));
|
||||
$x = str_pad($x, $length, "\0", STR_PAD_LEFT);
|
||||
$y = str_pad($y, $length, "\0", STR_PAD_LEFT);
|
||||
$z = str_pad($z, $length, "\0", STR_PAD_LEFT);
|
||||
return $x ^ $y ^ $z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two BinaryFieldIntegers.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function add(self $y): Integer
|
||||
{
|
||||
static::checkInstance($this, $y);
|
||||
|
||||
$length = strlen(static::$modulo[$this->instanceID]);
|
||||
|
||||
$x = str_pad($this->value, $length, "\0", STR_PAD_LEFT);
|
||||
$y = str_pad($y->value, $length, "\0", STR_PAD_LEFT);
|
||||
|
||||
return new static($this->instanceID, $x ^ $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts two BinaryFieldIntegers.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function subtract(self $x): Integer
|
||||
{
|
||||
return $this->add($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two BinaryFieldIntegers.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function multiply(self $y): Integer
|
||||
{
|
||||
static::checkInstance($this, $y);
|
||||
|
||||
return new static($this->instanceID, static::polynomialMultiply($this->value, $y->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the modular inverse of a BinaryFieldInteger
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function modInverse(): Integer
|
||||
{
|
||||
$remainder0 = static::$modulo[$this->instanceID];
|
||||
$remainder1 = $this->value;
|
||||
|
||||
if ($remainder1 == '') {
|
||||
return new static($this->instanceID);
|
||||
}
|
||||
|
||||
$aux0 = "\0";
|
||||
$aux1 = "\1";
|
||||
while ($remainder1 != "\1") {
|
||||
[$q, $r] = static::polynomialDivide($remainder0, $remainder1);
|
||||
$remainder0 = $remainder1;
|
||||
$remainder1 = $r;
|
||||
// the auxiliary in row n is given by the sum of the auxiliary in
|
||||
// row n-2 and the product of the quotient and the auxiliary in row
|
||||
// n-1
|
||||
$temp = static::polynomialMultiply($aux1, $q);
|
||||
$aux = str_pad($aux0, strlen($temp), "\0", STR_PAD_LEFT) ^
|
||||
str_pad($temp, strlen($aux0), "\0", STR_PAD_LEFT);
|
||||
$aux0 = $aux1;
|
||||
$aux1 = $aux;
|
||||
}
|
||||
|
||||
$temp = new static($this->instanceID);
|
||||
$temp->value = ltrim($aux1, "\0");
|
||||
return $temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides two PrimeFieldIntegers.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function divide(self $x): Integer
|
||||
{
|
||||
static::checkInstance($this, $x);
|
||||
|
||||
$x = $x->modInverse();
|
||||
return $this->multiply($x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate
|
||||
*
|
||||
* A negative number can be written as 0-12. With modulos, 0 is the same thing as the modulo
|
||||
* so 0-12 is the same thing as modulo-12
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function negate()
|
||||
{
|
||||
$x = str_pad($this->value, strlen(static::$modulo[$this->instanceID]), "\0", STR_PAD_LEFT);
|
||||
|
||||
return new static($this->instanceID, $x ^ static::$modulo[$this->instanceID]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the modulo
|
||||
*/
|
||||
public static function getModulo(int $instanceID): string
|
||||
{
|
||||
return static::$modulo[$instanceID];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Integer to a byte string (eg. base-256).
|
||||
*/
|
||||
public function toBytes(): string
|
||||
{
|
||||
return str_pad($this->value, strlen(static::$modulo[$this->instanceID]), "\0", STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Integer to a hex string (eg. base-16).
|
||||
*/
|
||||
public function toHex(): string
|
||||
{
|
||||
return Strings::bin2hex($this->toBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Integer to a bit string (eg. base-2).
|
||||
*/
|
||||
public function toBits(): string
|
||||
{
|
||||
//return str_pad(BinaryField::base256ToBase2($this->value), strlen(static::$modulo[$this->instanceID]), '0', STR_PAD_LEFT);
|
||||
return BinaryField::base256ToBase2($this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Integer to a BigInteger
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toBigInteger()
|
||||
{
|
||||
return new BigInteger($this->value, 256);
|
||||
}
|
||||
|
||||
/**
|
||||
* __toString() magic method
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->toBigInteger();
|
||||
}
|
||||
|
||||
/**
|
||||
* __debugInfo() magic method
|
||||
*/
|
||||
public function __debugInfo()
|
||||
{
|
||||
return ['value' => $this->toHex()];
|
||||
}
|
||||
}
|
||||
24
qa-tool/htdocs/oidc/phpseclib/Math/Common/FiniteField.php
Normal file
24
qa-tool/htdocs/oidc/phpseclib/Math/Common/FiniteField.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Finite Fields Base Class
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
namespace phpseclib3\Math\Common;
|
||||
|
||||
/**
|
||||
* Finite Fields
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class FiniteField
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Finite Field Integer Base Class
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
namespace phpseclib3\Math\Common\FiniteField;
|
||||
|
||||
/**
|
||||
* Finite Field Integer
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
abstract class Integer implements \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* JSON Serialize
|
||||
*
|
||||
* Will be called, automatically, when json_encode() is called on a BigInteger object.
|
||||
*
|
||||
* PHP Serialize isn't supported because unserializing would require the factory be
|
||||
* serialized as well and that just sounds like too much
|
||||
*
|
||||
* @return array{hex: string}
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return ['hex' => $this->toHex(true)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Integer to a hex string (eg. base-16).
|
||||
*/
|
||||
abstract public function toHex(): string;
|
||||
}
|
||||
110
qa-tool/htdocs/oidc/phpseclib/Math/PrimeField.php
Normal file
110
qa-tool/htdocs/oidc/phpseclib/Math/PrimeField.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Prime Finite Fields
|
||||
*
|
||||
* Utilizes the factory design pattern
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://pear.php.net/package/Math_BigInteger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace phpseclib3\Math;
|
||||
|
||||
use phpseclib3\Math\Common\FiniteField;
|
||||
use phpseclib3\Math\PrimeField\Integer;
|
||||
|
||||
/**
|
||||
* Prime Finite Fields
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class PrimeField extends FiniteField
|
||||
{
|
||||
/**
|
||||
* Instance Counter
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $instanceCounter = 0;
|
||||
|
||||
/**
|
||||
* Keeps track of current instance
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $instanceID;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public function __construct(BigInteger $modulo)
|
||||
{
|
||||
if (!$modulo->isPrime()) {
|
||||
throw new \phpseclib3\Exception\UnexpectedValueException('PrimeField requires a prime number be passed to the constructor');
|
||||
}
|
||||
|
||||
$this->instanceID = self::$instanceCounter++;
|
||||
Integer::setModulo($this->instanceID, $modulo);
|
||||
Integer::setRecurringModuloFunction($this->instanceID, $modulo->createRecurringModuloFunction());
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a custom defined modular reduction function
|
||||
*/
|
||||
public function setReduction(\Closure $func): void
|
||||
{
|
||||
$this->reduce = $func->bindTo($this, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of a dynamically generated PrimeFieldInteger class
|
||||
*/
|
||||
public function newInteger(BigInteger $num): Integer
|
||||
{
|
||||
return new Integer($this->instanceID, $num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an integer on the finite field between one and the prime modulo
|
||||
*/
|
||||
public function randomInteger(): Integer
|
||||
{
|
||||
static $one;
|
||||
if (!isset($one)) {
|
||||
$one = new BigInteger(1);
|
||||
}
|
||||
|
||||
return new Integer($this->instanceID, BigInteger::randomRange($one, Integer::getModulo($this->instanceID)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the modulo in bytes
|
||||
*/
|
||||
public function getLengthInBytes(): int
|
||||
{
|
||||
return Integer::getModulo($this->instanceID)->getLengthInBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the modulo in bits
|
||||
*/
|
||||
public function getLength(): int
|
||||
{
|
||||
return Integer::getModulo($this->instanceID)->getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
Integer::cleanupCache($this->instanceID);
|
||||
}
|
||||
}
|
||||
395
qa-tool/htdocs/oidc/phpseclib/Math/PrimeField/Integer.php
Normal file
395
qa-tool/htdocs/oidc/phpseclib/Math/PrimeField/Integer.php
Normal file
@@ -0,0 +1,395 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Prime Finite Fields
|
||||
*
|
||||
* PHP version 5 and 7
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2017 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
namespace phpseclib3\Math\PrimeField;
|
||||
|
||||
use phpseclib3\Common\Functions\Strings;
|
||||
use phpseclib3\Exception\UnexpectedValueException;
|
||||
use phpseclib3\Math\BigInteger;
|
||||
use phpseclib3\Math\Common\FiniteField\Integer as Base;
|
||||
|
||||
/**
|
||||
* Prime Finite Fields
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class Integer extends Base
|
||||
{
|
||||
/**
|
||||
* Holds the PrimeField's value
|
||||
*
|
||||
* @var BigInteger
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* Keeps track of current instance
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $instanceID;
|
||||
|
||||
/**
|
||||
* Holds the PrimeField's modulo
|
||||
*
|
||||
* @var array<int, BigInteger>
|
||||
*/
|
||||
protected static $modulo;
|
||||
|
||||
/**
|
||||
* Holds a pre-generated function to perform modulo reductions
|
||||
*
|
||||
* @var array<int, callable(BigInteger):BigInteger>
|
||||
*/
|
||||
protected static $reduce;
|
||||
|
||||
/**
|
||||
* Zero
|
||||
*
|
||||
* @var BigInteger
|
||||
*/
|
||||
protected static $zero;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public function __construct(int $instanceID, ?BigInteger $num = null)
|
||||
{
|
||||
$this->instanceID = $instanceID;
|
||||
if (!isset($num)) {
|
||||
$this->value = clone static::$zero[static::class];
|
||||
} else {
|
||||
$reduce = static::$reduce[$instanceID];
|
||||
$this->value = $reduce($num);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the modulo for a given instance
|
||||
*/
|
||||
public static function setModulo(int $instanceID, BigInteger $modulo): void
|
||||
{
|
||||
static::$modulo[$instanceID] = $modulo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the modulo for a given instance
|
||||
*/
|
||||
public static function setRecurringModuloFunction(int $instanceID, callable $function): void
|
||||
{
|
||||
static::$reduce[$instanceID] = $function;
|
||||
if (!isset(static::$zero[static::class])) {
|
||||
static::$zero[static::class] = new BigInteger();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the modulo for a given instance
|
||||
*/
|
||||
public static function cleanupCache(int $instanceID): void
|
||||
{
|
||||
unset(static::$modulo[$instanceID]);
|
||||
unset(static::$reduce[$instanceID]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the modulo
|
||||
*/
|
||||
public static function getModulo(int $instanceID): BigInteger
|
||||
{
|
||||
return static::$modulo[$instanceID];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a parameter to see if it's of the right instance
|
||||
*
|
||||
* Throws an exception if the incorrect class is being utilized
|
||||
*/
|
||||
public static function checkInstance(self $x, self $y): void
|
||||
{
|
||||
if ($x->instanceID != $y->instanceID) {
|
||||
throw new UnexpectedValueException('The instances of the two PrimeField\Integer objects do not match');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the equality of two numbers.
|
||||
*/
|
||||
public function equals(self $x): bool
|
||||
{
|
||||
static::checkInstance($this, $x);
|
||||
|
||||
return $this->value->equals($x->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two numbers.
|
||||
*/
|
||||
public function compare(self $x): int
|
||||
{
|
||||
static::checkInstance($this, $x);
|
||||
|
||||
return $this->value->compare($x->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two PrimeFieldIntegers.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function add(self $x): Integer
|
||||
{
|
||||
static::checkInstance($this, $x);
|
||||
|
||||
$temp = new static($this->instanceID);
|
||||
$temp->value = $this->value->add($x->value);
|
||||
if ($temp->value->compare(static::$modulo[$this->instanceID]) >= 0) {
|
||||
$temp->value = $temp->value->subtract(static::$modulo[$this->instanceID]);
|
||||
}
|
||||
|
||||
return $temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts two PrimeFieldIntegers.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function subtract(self $x): Integer
|
||||
{
|
||||
static::checkInstance($this, $x);
|
||||
|
||||
$temp = new static($this->instanceID);
|
||||
$temp->value = $this->value->subtract($x->value);
|
||||
if ($temp->value->isNegative()) {
|
||||
$temp->value = $temp->value->add(static::$modulo[$this->instanceID]);
|
||||
}
|
||||
|
||||
return $temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two PrimeFieldIntegers.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function multiply(self $x): Integer
|
||||
{
|
||||
static::checkInstance($this, $x);
|
||||
|
||||
return new static($this->instanceID, $this->value->multiply($x->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides two PrimeFieldIntegers.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function divide(self $x): Integer
|
||||
{
|
||||
static::checkInstance($this, $x);
|
||||
|
||||
$denominator = $x->value->modInverse(static::$modulo[$this->instanceID]);
|
||||
return new static($this->instanceID, $this->value->multiply($denominator));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs power operation on a PrimeFieldInteger.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function pow(BigInteger $x): Integer
|
||||
{
|
||||
$temp = new static($this->instanceID);
|
||||
$temp->value = $this->value->powMod($x, static::$modulo[$this->instanceID]);
|
||||
|
||||
return $temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the square root
|
||||
*
|
||||
* @link https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm
|
||||
* @return static|false
|
||||
*/
|
||||
public function squareRoot()
|
||||
{
|
||||
static $one, $two;
|
||||
if (!isset($one)) {
|
||||
$one = new BigInteger(1);
|
||||
$two = new BigInteger(2);
|
||||
}
|
||||
$reduce = static::$reduce[$this->instanceID];
|
||||
$p_1 = static::$modulo[$this->instanceID]->subtract($one);
|
||||
$q = clone $p_1;
|
||||
$s = BigInteger::scan1divide($q);
|
||||
[$pow] = $p_1->divide($two);
|
||||
for ($z = $one; !$z->equals(static::$modulo[$this->instanceID]); $z = $z->add($one)) {
|
||||
$temp = $z->powMod($pow, static::$modulo[$this->instanceID]);
|
||||
if ($temp->equals($p_1)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$m = new BigInteger($s);
|
||||
$c = $z->powMod($q, static::$modulo[$this->instanceID]);
|
||||
$t = $this->value->powMod($q, static::$modulo[$this->instanceID]);
|
||||
[$temp] = $q->add($one)->divide($two);
|
||||
$r = $this->value->powMod($temp, static::$modulo[$this->instanceID]);
|
||||
|
||||
while (!$t->equals($one)) {
|
||||
for ($i = clone $one; $i->compare($m) < 0; $i = $i->add($one)) {
|
||||
if ($t->powMod($two->pow($i), static::$modulo[$this->instanceID])->equals($one)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($i->compare($m) == 0) {
|
||||
return false;
|
||||
}
|
||||
$b = $c->powMod($two->pow($m->subtract($i)->subtract($one)), static::$modulo[$this->instanceID]);
|
||||
$m = $i;
|
||||
$c = $reduce($b->multiply($b));
|
||||
$t = $reduce($t->multiply($c));
|
||||
$r = $reduce($r->multiply($b));
|
||||
}
|
||||
|
||||
return new static($this->instanceID, $r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is Odd?
|
||||
*/
|
||||
public function isOdd(): bool
|
||||
{
|
||||
return $this->value->isOdd();
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate
|
||||
*
|
||||
* A negative number can be written as 0-12. With modulos, 0 is the same thing as the modulo
|
||||
* so 0-12 is the same thing as modulo-12
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function negate(): Integer
|
||||
{
|
||||
return new static($this->instanceID, static::$modulo[$this->instanceID]->subtract($this->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Integer to a byte string (eg. base-256).
|
||||
*/
|
||||
public function toBytes(): string
|
||||
{
|
||||
if (isset(static::$modulo[$this->instanceID])) {
|
||||
$length = static::$modulo[$this->instanceID]->getLengthInBytes();
|
||||
return str_pad($this->value->toBytes(), $length, "\0", STR_PAD_LEFT);
|
||||
}
|
||||
return $this->value->toBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Integer to a hex string (eg. base-16).
|
||||
*/
|
||||
public function toHex(): string
|
||||
{
|
||||
return Strings::bin2hex($this->toBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Integer to a bit string (eg. base-2).
|
||||
*/
|
||||
public function toBits(): string
|
||||
{
|
||||
// return $this->value->toBits();
|
||||
static $length;
|
||||
if (!isset($length)) {
|
||||
$length = static::$modulo[$this->instanceID]->getLength();
|
||||
}
|
||||
|
||||
return str_pad($this->value->toBits(), $length, '0', STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the w-ary non-adjacent form (wNAF)
|
||||
*
|
||||
* @param int $w optional
|
||||
* @return array<int, int>
|
||||
*/
|
||||
public function getNAF(int $w = 1): array
|
||||
{
|
||||
$w++;
|
||||
|
||||
$mask = new BigInteger((1 << $w) - 1);
|
||||
$sub = new BigInteger(1 << $w);
|
||||
//$sub = new BigInteger(1 << ($w - 1));
|
||||
$d = $this->toBigInteger();
|
||||
$d_i = [];
|
||||
|
||||
$i = 0;
|
||||
while ($d->compare(static::$zero[static::class]) > 0) {
|
||||
if ($d->isOdd()) {
|
||||
// start mods
|
||||
|
||||
$bigInteger = $d->testBit($w - 1) ?
|
||||
$d->bitwise_and($mask)->subtract($sub) :
|
||||
//$sub->subtract($d->bitwise_and($mask)) :
|
||||
$d->bitwise_and($mask);
|
||||
// end mods
|
||||
$d = $d->subtract($bigInteger);
|
||||
$d_i[$i] = (int) $bigInteger->toString();
|
||||
} else {
|
||||
$d_i[$i] = 0;
|
||||
}
|
||||
$shift = !$d->equals(static::$zero[static::class]) && $d->bitwise_and($mask)->equals(static::$zero[static::class]) ? $w : 1; // $w or $w + 1?
|
||||
$d = $d->bitwise_rightShift($shift);
|
||||
while (--$shift > 0) {
|
||||
$d_i[++$i] = 0;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $d_i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an Integer to a BigInteger
|
||||
*/
|
||||
public function toBigInteger(): BigInteger
|
||||
{
|
||||
return clone $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* __toString() magic method
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* __debugInfo() magic method
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function __debugInfo()
|
||||
{
|
||||
return ['value' => $this->toHex()];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user