PHP Conference Japan 2024

bcpowmod

(PHP 5, PHP 7, PHP 8)

bcpowmod将任意精度数字提升到另一个数字的幂,并由指定的模数进行归约

描述

bcpowmod(
    string $num,
    string $exponent,
    string $modulus,
    ?int $scale = null
): string

使用快速幂取模方法计算 numexponent 次幂,并对 modulus 取模。

参数

num

底数,表示为整数字符串(即,比例必须为零)。

exponent

指数,表示为非负整数字符串(即,比例必须为零)。

modulus

模数,表示为整数字符串(即,比例必须为零)。

scale
此参数用于设置结果中小数点后的位数。如果为 null,则默认为使用 bcscale() 设置的默认比例,或者回退到 bcmath.scale INI 指令的值。

返回值

返回结果字符串。

错误/异常

此函数在以下情况下抛出 ValueError 异常:

  • numexponentmodulus 不是格式良好的 BCMath 数字字符串
  • numexponentmodulus 包含小数部分
  • exponent 为负值
  • scale 超出有效范围

如果 modulus0,则此函数抛出 DivisionByZeroError 异常。

变更日志

版本 描述
8.0.0 scale 现在可以为空。
8.0.0 如果 exponent 为负值,则现在抛出 ValueError 异常,而不是返回 false
8.0.0 除以 0 现在抛出 DivisionByZeroError 异常,而不是返回 false

示例

以下两个语句在功能上是相同的。bcpowmod() 版本的执行时间较短,并且可以接受更大的参数。

<?php
$a
= bcpowmod($x, $y, $mod);

$b = bcmod(bcpow($x, $y), $mod);

// $a 和 $b 相等。

?>

注释

注意:

因为此方法使用模运算,所以非正整数可能会产生意外结果。

参见

  • bcpow() - 将任意精度数字提升到另一个数字的幂
  • bcmod() - 获取任意精度数字的模数

添加注释

用户贡献的注释 3 条注释

ewilde aht bsmdevelopment dawt com
19 年前
低于 5 的版本的 PHP 没有 bcpowmod 函数。此例程使用 bcdiv、bcmod 和 bcmul 模拟此函数。提供 bcpowmod 函数非常有用,因为它通常用于实现 RSA 算法。

bcpowmod(v, e, m) 函数据说是等效于 bcmod(bcpow(v, e), m)。但是,对于 RSA 算法中用作密钥的大数,bcpow 函数生成的大数会导致溢出。对于任何大于几万的指数,bcpow 都会溢出并返回 1。

此例程将迭代循环,对每次迭代的指数中的每一位进行平方,并对模数取模。指数在每次迭代中向右移动一位。当它被简化为零时,计算结束。

此方法可能比 bcpowmod 慢,但至少它有效。

function PowModSim($Value, $Exponent, $Modulus)
{
// 检查是否需要模拟。
if (function_exists("bcpowmod"))
return (bcpowmod($Value, $Exponent, $Modulus));

// 循环直到指数减少到零。
$Result = "1";

while (TRUE)
{
if (bcmod($Exponent, 2) == "1")
$Result = bcmod(bcmul($Result, $Value), $Modulus);

if (($Exponent = bcdiv($Exponent, 2)) == "0") break;

$Value = bcmod(bcmul($Value, $Value), $Modulus);
}

return ($Result);
}
rrasss at gmail dot com
18 年前
但是,如果您阅读了他的完整注释,您会看到这一段
“bcpowmod(v, e, m) 函数据说是等效于 bcmod(bcpow(v, e), m)。但是,对于 RSA 算法中用作密钥的大数,bcpow 函数生成的大数会导致溢出。对于任何大于几万的指数,bcpow 都会溢出并返回 1。”

因此,如果您使用较大的指数,“任何大于几万的指数”,您仍然可以(并且应该使用此函数,而不是 bcmod(bcpow(v, e), m))。
laysoft at gmail dot com
17 年前
我发现了一种在 PHP 4 上模拟 bcpowmod 的更好方法,它也适用于非常大的数字

function powmod($m,$e,$n) {
if (intval(PHP_VERSION)>4) {
return(bcpowmod($m,$e,$n));
} else {
$r="";
while ($e!="0") {
$t=bcmod($e,"4096");
$r=substr("000000000000".decbin(intval($t)),-12).$r;
$e=bcdiv($e,"4096");
}
$r=preg_replace("!^0+!","",$r);
if ($r=="") $r="0";
$m=bcmod($m,$n);
$erb=strrev($r);
$q="1";
$a[0]=$m;
for ($i=1;$i<strlen($erb);$i++) {
$a[$i]=bcmod(bcmul($a[$i-1],$a[$i-1]),$n);
}
for ($i=0;$i<strlen($erb);$i++) {
if ($erb[$i]=="1") {
$q=bcmod(bcmul($q,$a[$i]),$n);
}
}
return($q);
}
}
To Top