1
0
mirror of https://github.com/danog/tgseclib.git synced 2024-12-02 17:48:00 +01:00
tgseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/EvalBarrett.php
2018-11-19 12:39:21 -06:00

117 lines
3.0 KiB
PHP

<?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
*
* @param BCMath $m
* @param string $class
* @return callable|void
*/
protected static function generateCustomReduction(BCMath $m, $class)
{
if (isset($n->reduce)) {
self::$custom_reduction = $n->reduce;
return $n->reduce;
}
$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;
}
}