Преобразование сложных функций поворота PHP для работы в 64-разрядной


Несколько лет назад мой веб-хостинг изменился с 32-разрядного на 64-разрядный, и критический PHP-скрипт перестал работать. Это произошло из-за того, что изменились операции <<и>> (сдвиг битов). Я смог решить свою проблему, заменив процедуры rotateleft и rotateright на rotateleft32 и rotateright32 следующим образом:

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);
}

Теперь я столкнулся с новым набором кода, который, похоже, имеет точно такую же проблему, но он сложнее:

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;
}

У меня есть три проблемы при попытке чтобы исправить это самостоятельно:

  1. Это не мой код, поэтому я не знаком с тем, что он пытается сделать.
  2. У меня больше нет 32-разрядного сервера, чтобы протестировать его на
  3. Я адекватен, но не эксперт в PHP.

Я хотел бы знать, видит ли кто-нибудь простое исправление, позволяющее этому коду работать на 64-разрядном сервере и давать тот же результат, что и на 32-разрядном сервере.

Если нет, то как бы вы порекомендовали мне отладить это, учитывая, что у меня нет 32-разрядного результата для сравнивать с чем?


Вот некоторое обсуждение этой проблемы и попытка заставить разработчика исправить ее: Как получить устаревший 32-битный keymaker.php Скрипт, работающий на 64-битной

Author: lkessler, 2012-03-25

1 answers

Отвечая на все четыре ваших вопроса:

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

Как упоминал Оли в исправлениях, вам потребуется настроить 32-разрядную виртуальную машину или chroot, зависит от операционной системы, на которой работает ваш сервер.

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

Как и выше, если это больше, чем просто точечная проблема, я рекомендую классика.

4. ( Исправление фактического кода)

Во-первых, фу. Нет документации, комментариев, повторяющейся логики и невыразительных имен переменных, которые не могут эффективно инкапсулировать свою логику. Это не самый худший код, который я видел, но я сочувствую вам здесь.

Тем не менее, результат не обязательно неправильно . Если у вас нет серии модульных тестов для этого в вашей базе кода, Я рекомендую добавить их.

Если вы хотите оценить эффективность этой функции, я настоятельно рекомендую сравнить ее с результатами алгоритмов, определенных в примечаниях здесь. В идеале вам понадобится одна из реализаций , наиболее близкая к этой эталонной реализации .

Кража одного из них с верхней части этой темы и повторное использование его для вашего 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;
}

(Неудивительно, что это похоже на реализацию, которую вы изначально предоставили.)

Почему я включаю $amount как часть спецификации? Просто: это не нарушает инкапсуляцию , как код, который вы рефакторируете. Похоже, что это может быть установлено в ($copya->e[0] & ECC_UPRBIT) ? 1 : 0 по мере необходимости.

Короче говоря: самый простой способ рефакторинга кода - это не обязательно смотреть на содержащуюся в нем логику. Иногда определение намерения и поиск хорошей эталонной реализации - это все это необходимо.

 26
Author: MrGomez, 2012-03-28 01:37:29