2017-06-25 18:02:54 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* BCMath Dynamic Barrett Modular Exponentiation Engine
|
|
|
|
*
|
|
|
|
* PHP version 5 and 7
|
|
|
|
*
|
|
|
|
* @category Math
|
|
|
|
* @package BigInteger
|
|
|
|
* @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
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace phpseclib\Math\BigInteger\Engines\BCMath\Reductions;
|
|
|
|
|
|
|
|
use phpseclib\Math\BigInteger\Engines\BCMath\Base;
|
|
|
|
use phpseclib\Math\BigInteger\Engines\BCMath;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* PHP Barrett Modular Exponentiation Engine
|
|
|
|
*
|
|
|
|
* @package PHP
|
|
|
|
* @author Jim Wigginton <terrafrost@php.net>
|
|
|
|
* @access public
|
|
|
|
*/
|
|
|
|
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.
|
|
|
|
*
|
|
|
|
* @param string $n
|
|
|
|
* @param string $m
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
protected static function reduce($n, $m)
|
|
|
|
{
|
|
|
|
$inline = self::$custom_reduction;
|
|
|
|
return $inline($n);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate Custom Reduction
|
|
|
|
*
|
2017-10-25 11:44:14 +02:00
|
|
|
* @param BCMath $m
|
2017-06-25 18:02:54 +02:00
|
|
|
* @param string $class
|
2017-08-03 09:15:16 +02:00
|
|
|
* @return callable|void
|
2017-06-25 18:02:54 +02:00
|
|
|
*/
|
|
|
|
protected static function generateCustomReduction(BCMath $m, $class)
|
|
|
|
{
|
2018-10-25 03:00:37 +02:00
|
|
|
if (isset($n->reduce)) {
|
|
|
|
self::$custom_reduction = $n->reduce;
|
|
|
|
return $n->reduce;
|
|
|
|
}
|
|
|
|
|
2017-06-25 18:02:54 +02:00
|
|
|
$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;
|
2018-10-25 03:00:37 +02:00
|
|
|
|
|
|
|
return $func;
|
2017-06-25 18:02:54 +02:00
|
|
|
}
|
|
|
|
}
|