Почему результат преобразования из шестнадцатеричной строки в строку base36 в C ++ отличается от результата той же операции в PHP?

Вот код C ++:

#include <stdio.h>
#include <openssl/sha.h>
#include <string>
#include <gmp.h>

std::string base36enc(std::string data){
mpz_t nr;
mpz_init(nr);
mpz_set_str(nr, data.c_str(), 16);
return std::string(mpz_get_str(NULL, 36, nr));
}

//sha512 function here...

int main(){
std::string data = "deadbeef1234d0";
printf("Raw data to base36:\t%s\n",base36enc(data).c_str());
printf("SHA512 data to b36:\t%s\n",base36enc(sha512(data)).c_str());
printf("SHA512 data only  :\t%s\n",sha512(data).c_str());

return 0;
}

И вывод:

Raw data to base36:     h55o0dxfmj4
SHA512 data to b36:     clldzg9hyfl5ihp0taww8rny0jxvz67rsk1w4og26zqyt4hdrya68yme09iwtew0tdq6aro9rk3jy2m3r2zpegumccc8ssrbnfr
SHA512 data only  :     4f3aff747e9ce090e5dfc5f23ce2a37233a21cfa2db7db70c984bc9ff8b263c9e02a6a485455c8042d10112f659a965e0bbf9645ee0c0e0c0824970dd879f667

Вот код PHP:

<?php
$data = "deadbeef1234d0";
echo "Raw data to base36: <b>".base_convert($data, 16, 36)."</b><br>";
echo "SHA512 data to b36: <b>".base_convert(hash(sha512,$data), 16, 36)."</b><br>";
echo "SHA512 data only  : <b>".hash(sha512,$data)."</b>";

И вывод PHP:

Raw data to base36: h55o0dxfmj4
SHA512 data to b36: g8804wccs0kc8w8ckkogoc8ssgcs8ccc0sgssgs4g0gok8k8kkgss0og44swkwsc
SHA512 data only  : 4f3aff747e9ce090e5dfc5f23ce2a37233a21cfa2db7db70c984bc9ff8b263c9e02a6a485455c8042d10112f659a965e0bbf9645ee0c0e0c0824970dd879f667

Зашифрованная строка, преобразованная в base36, отличается в PHP и C ++. Но не шифрование вызывает проблему (результаты хеширования всегда совпадают). Если изменить последний символ в данных на 1 или любую шестнадцатеричную цифру больше 0, исходные данные будут отличаться, и я не могу понять, почему!

Например, если данные «deadbeef1234dе«вывод C ++ для raw-data-to-base36 будет» h55o0dxfmjJ«и вывод PHP будет» h55o0dxfmjК».

Может ли кто-нибудь помочь мне найти причину этой «магии»?

0

Решение

В PHP base_convert Функция преобразует «число» между произвольными основаниями и может потерять точность при больших числах из-за свойств, связанных с используемым внутренним типом «double» или «float». Прочитайте больше.

Попробуйте эту функцию вместо base_convert:

Код

function bignumber_base_convert($str, $frombase = 10, $tobase = 36)
{
$str = trim($str);
if (intval($frombase) != 10) {
$len = strlen($str);
$q = 0;
for ($i = 0; $i < $len; $i++) {
$r = base_convert($str[$i], $frombase, 10);
$q = bcadd(bcmul($q, $frombase), $r);
}
} else {
$q = $str;
}

if (intval($tobase) != 10) {
$s = '';
while (bccomp($q, '0', 0) > 0) {
$r = intval(bcmod($q, $tobase));
$s = base_convert($r, 10, $tobase) . $s;
$q = bcdiv($q, $tobase, 0);
}
} else {
$s = $q;
}

return $s;
}

использование

echo bignumber_base_convert(hash('sha512',$data), 16, 36) . "\n";

Результат

clldzg9hyfl5ihp0taww8rny0jxvz67rsk1w4og26zqyt4hdrya68yme09iwtew0tdq6aro9rk3jy2m3r2zpegumccc8ssrbnfr
1

Другие решения

Других решений пока нет …