Преобразование частичного хеш-кода MD5 в длинный - PullRequest
1 голос
/ 25 июня 2011

Я использую алгоритм MD5 для хеширования ключа для хеш-таблицы на диске (я знаю, сомнительно, является ли это лучшим алгоритмом для этого, но я сейчас с ним разбираюсь. Проблема в том,обобщается на любой алгоритм, который создает массив байтов).Моя проблема заключается в следующем:

Размер хеш-кода определяет количество комбинаций (сегментов) в хеш-таблице.Поскольку MD5 128-битный, существует огромное количество комбинаций (~ 3.4e38), что слишком велико для моей цели.Итак, я хочу выделить первые n бит байтового массива, которые производит MD5, и преобразовать их в длинное (или ulong) значение.Поскольку MD5 создает массив байтов, это было бы легко сделать, если бы я хотел получить целое число байтов, но это приводит к слишком большому скачку числа комбинаций.Я считаю, что одно-битная версия намного сложнее.

Цель:

n = 10  // I.e. I want 2^10 combinations
long pos = someFcn(byte[] key, n)

где ключ - это хешируемое значение, а n - количество битов результата MD5, которые я хочу использовать.Тогда Pos будет целым числом от 0 до 1023 (в случае n = 10).Если n = 11, код будет от 0 до 2 ^ 11-1 = 2027 и т. Д. Должно быть несколько быстрым / эффективным.

Не кажется таким уж сложным, но это ускользает от меня.Любая помощь приветствуется.Благодарю.

Ответы [ 3 ]

1 голос
/ 25 июня 2011

Сначала преобразуйте первые четыре байта в целое число с BitConverter.ToInt32. Он получает четыре байта, несмотря ни на что, но это, вероятно, не сделает его заметно медленнее, поскольку вы все равно работаете с 32-битными регистрами для остальной части вычислений и такими сложными вещами, как «если это <16, то сделайте это с первые два байта "только усложнят </p>

Затем, учитывая это целое число, берут младшие N битов. Если вы действительно хотите, чтобы определенное количество битов [степень двух чисел] не было известно во время компиляции, ~((-1)<<N) - хороший прием для получения 2 ^ N-1.

Или вы могли бы просто использовать ToUInt32 вместо этого и по модулю простого числа [вместо этого может быть немного лучше преобразовать в UInt64, тогда у вас будет полностью половина битов, в данном случае]

0 голосов
/ 25 июня 2011

Если у вас есть такой массив,

unsigned char data[2000];

, то вы можете просто вычеркнуть первые n битов в целое число, например:

typedef unsigned long long int MyInt;

MyInt scrape(size_t n, unsigned char * data)
{
    MyInt result = 0;
    size_t b;

    for (b = 0; b < n / 8; ++b)
    {
       result <<= 8;
       result += data[b];
    }

    const size_t remaining_bits = n % 8;
    result <<= remaining_bits;
    result += (data[b] >> (8 - remaining_bits));

    return result;
 }

Я предполагаю, чтоCHAR_BITS == 8, не стесняйтесь обобщать код, если хотите.Также размер массива умноженный на 8 должен быть не менее n.

0 голосов
/ 25 июня 2011

Для получения первых 10 битов, например:

int result = ((int)key[0] << 2) | (((int)key[1] >> 6) & 0x03)
...