Хорошо, я использую необработанный хэш SHA1 для заполнения генератора псевдослучайных чисел Мерсенна Твистера
генератор дает мне возможность посеять либо с беззнаковым длинным, либо с массивом беззнаковых длинных
класс SHA1, который я использую, дает мне хэш в виде 20-байтового массива беззнаковых символов
Я подумал, что мог бы преобразовать этот массив символов в массив длинных, чтобы получить работающее начальное число, но как я могу узнать, как долго получается массив длинных?
пример кода:
CSHA1 sha1;
sha1.Update((unsigned char*)key, size_key);
sha1.Final();
unsigned char* hash;
sha1.GetHash(hash);
// Seed the random with the key
MTRand mt((unsigned long*)hash, <size of array of longs>);
Я надеюсь, что нет потери данных (так как ни один байт не сбрасывается), так как мне нужно, чтобы криптография оставалась безопасной
Ты можешь сказать
sizeof(unsigned long) / sizeof(unsigned char)
чтобы получить количество октетов в длинном.
Однако есть две потенциальные проблемы с простым кастом.
Во-первых, массив символов может быть неправильно выровнен. На некоторых процессорах это может вызвать ловушку. На других это просто замедляет выполнение.
Во-вторых, вы просите о проблемах с порядком байтов, если программа должна работать одинаково на разных архитектурах.
Вы можете решить обе проблемы, явно скопировав байты в массив long. Непроверенный код:
const int bytes_per_long = sizeof(unsigned long) / sizeof(unsigned char);
unsigned long hash_copy[key_length_in_bytes / bytes_per_long];
int i_hash = 0;
for (int i_copy = 0; i_copy < sizeof hash_copy / sizeof hash_copy[0]; i_copy++) {
unsigned long b = 0;
for (int i_byte = 0; i_byte < bytes_per_long; i_byte++)
b = (b << 8) | hash[i_hash++];
hash_copy[i_copy] = b;
}
// Now use hash_copy.
Ты можешь использовать len_of_chars * sizeof(char) / sizeof(long)
, где len_of_chars
предположительно 20.
Ваша библиотека кажется, предполагает 32-разрядный unsigned long
s, так что нет больше вреда, если вы делаете то же самое. На самом деле, я бы пошел так далеко, чтобы предположить, 8-битный unsigned char
и, возможно, даже незаполненные представления с прямым порядком байтов для обоих. Таким образом, вы могли бы использовать простое приведение (хотя я бы использовал reinterpret_cast
) или, может быть, @ Джина memcpy
образец для выравнивания.
Портативный код *, однако, должен использовать <cstdint>
, uint#_t
Типы в них и кусочно, побочное копирование для преобразования:
uint32_t littleEndianInt8sToInt32(uint8_t bytes[4]) {
return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
}
…и лучшие имена. Извините, здесь уже поздно 🙂
*: Хотя, конечно, stdint
сам не очень переносим (> = C ++ 11), и типы с точной шириной не обязательно будут в нем. Иронический.