将复杂的PHP旋转函数转换为64位工作

lke*_*ler 10 php algorithm bit-manipulation 32bit-64bit

几年前,我的webhost从32位变为64位,并且一个关键的PHP脚本停止工作.这是由于<<和>>(位移)操作已经改变.我能够通过用rotateleft32和rotateright32替换rotateleft和rotateright例程来解决我的问题,如下所示:

function rotateleft($value, $numleft) {
  return (($value << $numleft) | ($value >> (32-$numleft)));
}
function rotateleft32($value, $numleft) {
  return ((($value << $numleft) | ($value >> (32-$numleft))) & 0xFFFFFFFF);
}

function rotateright($value, $numright) {
  return (($value >> $numright) | ($value << (32-$numright)));
}
function rotateright32($value, $numright) {
  return ((($value >> $numright) | ($value << (32-$numright))) & 0xFFFFFFFF);
}
Run Code Online (Sandbox Code Playgroud)

我现在遇到了一组似乎完全相同的新代码,但它更复杂:

function ECC_RotateLeft($a)
{
    $copya = makecopy($a);
    $bit = ($copya->e[0] & ECC_UPRBIT) ? 1 : 0;

    /* looped
    for ($i = 0; $i < ECC_MAXLONG - 1; $i++)
    $copya->e[$i] = ($copya->e[$i] << 1) | (($copya->e[$i + 1] & ECC_MSB) ? 1 : 0);
    $copya->e[0] &= ECC_UPRMASK;
    looped */

    /* unlooped */
    // These lines are optimized for ECC_MAXLONG==4 only!
    $bit = ($copya->e[0] & ECC_UPRBIT) ? 1 : 0;
    $copya->e[0] = (($copya->e[0] << 1) & ECC_UPRMASK) | (($copya->e[1] & ECC_MSB) ? 1 : 0);
    $copya->e[1] = ($copya->e[1] << 1) | (($copya->e[2] & ECC_MSB) ? 1 : 0);
    $copya->e[2] = ($copya->e[2] << 1) | (($copya->e[3] & ECC_MSB) ? 1 : 0);
    /* unlooped */

    $copya->e[3] = ($copya->e[3] << 1) | $bit;
    return $copya;
}

function ECC_RotateRight($a)
{
    $copya = makecopy($a);
    $bit = ($copya->e[ECC_NUMWORD] & 1) ? ECC_UPRBIT : 0;

    /* looped
    for ($i = ECC_MAXLONG - 1; $i > 0; $i--)
    $copya->e[$i] = (($copya->e[$i] >> 1) & 0x7FFFFFFF) | (($copya->e[$i - 1] & 1) ? ECC_MSB : 0);
    looped */

    /* unlooped */
    // Thes lines are optimized for ECC_MAXLONG==4 only!
    $copya->e[3] = (($copya->e[3] >> 1) & 0x7FFFFFFF) | (($copya->e[2] & 1) ? ECC_MSB : 0);
    $copya->e[2] = (($copya->e[2] >> 1) & 0x7FFFFFFF) | (($copya->e[1] & 1) ? ECC_MSB : 0);
    $copya->e[1] = (($copya->e[1] >> 1) & 0x7FFFFFFF) | (($copya->e[0] & 1) ? ECC_MSB : 0);
    /* unlooped */

    $copya->e[0] = (($copya->e[0] >> 1) & 0x7FFFFFFF) | $bit;
    return $copya;
}
Run Code Online (Sandbox Code Playgroud)

我自己试图解决这个问题有三个问题:

  1. 这不是我的代码,所以我不熟悉它正在尝试做什么.
  2. 我不再有32位服务器来测试它
  3. 我很充足,但不是PHP的专家.

我想知道是否有人确实看到一个简单的修复程序,允许此代码在64位服务器上运行,并提供与在32位服务器上相同的结果.

如果没有,鉴于我没有32比特的结果进行比较,你会如何推荐我调试?


以下是关于这个问题的一些讨论,并试图让开发人员修复它: 如何获取过时的32位keymaker.php脚本工作64位

MrG*_*mez 26

回答你的所有四个问题:

 1. It is not my code, so I am not familiar with what it is trying to do.

虽然我可以详细介绍跟踪和调试过程,但我会推荐经典.如果这是你的日常工作,或者你对将来的重构代码不仅仅有兴趣,我强烈建议你选择这个.

 2. I no longer have a 32-bit server to test it against

正如Oli在勘误表中所提到的,您将需要设置32位VMchroot,具体取决于您的服务器运行的操作系统.

 3. I am adequate, but not an expert in PHP.

如上所述,如果这不仅仅是一个点的问题更多,我推荐 经典.

 4. (修复实际代码)

首先,eww.没有文档,评论残缺,重复逻辑和无法解释的变量名称无法有效地封装其逻辑.这不是我见过的最糟糕的代码,但我在这里同情你.

不过,结果并不一定是错的.如果您的代码库中没有针对它的一系列单元测试,我建议您添加它们.

如果您希望对此功能的效率进行基准测试,我强烈建议将其与此处注释中定义的算法结果进行比较.理想情况下,您需要一个最接近此参考实现的实现.

从该线程的顶部窃取一个并将其重新用于您的API:

function ECC_RotateLeft($value,$amount) {
    if ($amount>0) {
        $amount %= 32;
        $value = ($value<<$amount) | ($value>>(32-$amount));
    }
    return $value;
}

function ECC_RotateRight($value,$amount) {
    if ($amount>0) {
        $amount %= 32;
        $value = ($value>>$amount) | ($value<<(32-$amount));
    }
    return $value;
}
Run Code Online (Sandbox Code Playgroud)

(毫不奇怪,这与您最初提供的实现类似.)

为什么我要将其$amount作为规范的一部分?简单:它不会像你重构的代码那样违反封装.看起来这可以($copya->e[0] & ECC_UPRBIT) ? 1 : 0根据需要设置.

简而言之:重构代码的最简单方法不一定是查看其包含的逻辑.有时,确定意图并找到一个好的参考实现就是所需要的.

  • @andreas唉,只有两个人的产卵.在撰写本文时,我只是一位谦逊的癌症研究员.:) (8认同)