【问题标题】:Converting a partial MD5 hash code into a long将部分 MD5 哈希码转换为长
【发布时间】:2011-06-24 21:56:17
【问题描述】:

我正在使用 MD5 算法对磁盘上的哈希表的密钥进行哈希处理(我知道这是否是用于此目的的最佳算法值得怀疑,但我现在就使用它。问题是可推广到任何产生字节数组的算法)。我的问题是这样的:

哈希码的大小决定了哈希表中组合(桶)的数量。由于 MD5 是 128 位的,因此有大量的组合(~ 3.4e38),这对我的目的来说太大了。所以我想做的是挑选 MD5 生成的字节数组的前 n 位,并将它们转换为长(或 ulong)值。由于 MD5 产生一个字节数组,如果我想要整数个字节,这很容易做到,但这会导致组合数量的跳跃太大。我发现单比特版本要复杂得多。

目标:

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

其中 key 是被散列的值,n 是我想要使用的 MD5 结果的位数。那么,Pos 将是一个从 0 到 1023 的整数(在 n = 10 的情况下)。如果 n = 11,代码将从 0 到 2^11-1 = 2027 等。必须有点快/高效。

似乎并不难,但它让我望而却步。任何帮助将非常感激。谢谢。

【问题讨论】:

  • 您需要在这里进行一些位移。不过,我不知道 C# 语法。

标签: c# arrays hash byte md5


【解决方案1】:

首先,将前四个字节转换为整数,使用BitConverter.ToInt32。无论如何它都会得到四个字节,但这可能不会让它明显变慢,因为无论如何你都在使用 32 位寄存器进行其余的计算,以及像“如果它小于 16 则使用前两个字节”只会让它更复杂

然后,给定该整数,取最低的 N 位。如果您真的想要在编译时未知的特定位数 [桶数的二次幂],~((-1)<<N) 是获得 2^N-1 的好方法。

或者您可以简单地使用 ToUInt32 并取模一个素数 [转换为 UInt64 可能会稍微好一点,那么在这种情况下,您已经有了完全一半的位开始]

【讨论】:

  • 优秀。谢谢, Random832 等人。会采用一些非常简单的方法,例如: UInt64 pos = 42; UInt64 掩码 = ~((-1)
  • 如果您对数字进行硬编码,我建议您只硬编码 15 或 0xF,如果 N 是可变的,则“技巧”适用于。
【解决方案2】:

获取前10位,例如:

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

【讨论】:

  • 有符号整数的右移是否定义明确?它不在 C 语言中,但我不懂 C#。
  • 是的,它定义明确。新位与符号位相同。
【解决方案3】:

如果你有这样的数组,

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

【讨论】:

    猜你喜欢
    • 2011-02-11
    • 1970-01-01
    • 2010-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多