【问题标题】:Is this the correct way to truncate a hash in C#?这是在 C# 中截断哈希的正确方法吗?
【发布时间】:2014-02-21 23:35:12
【问题描述】:

我需要对输入字符串进行哈希处理并生成 14 位十进制数字作为输出。

math I am using 告诉我,我最多可以有一个 46 位无符号整数。

我知道 46 位 uint 意味着任何潜在的哈希函数的抗碰撞性更低。但是,我创建的哈希数将冲突概率保持在可接受的范围内。

如果社区能帮助我验证我将哈希截断为 46 位的方法是否可靠,我将不胜感激。我有一种直觉,有优化和/或更简单的方法可以做到这一点。我的函数如下(调用该函数时bitLength为46):

    public static UInt64 GetTruncatedMd5Hash(string input, int bitLength)
    {
        var md5Hash = MD5.Create();

        byte[] fullHashBytes = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

        var fullHashBits = new BitArray(fullHashBytes);

        // BitArray stores LSB of each byte in lowest indexes, so reversing...
        ReverseBitArray(fullHashBits);

        // truncate by copying only number of bits specified by bitLength param
        var truncatedHashBits = new BitArray(bitLength);
        for (int i = 0; i < bitLength - 1; i++)
        {
            truncatedHashBits[i] = fullHashBits[i];
        }

        byte[] truncatedHashBytes = new byte[8];

        truncatedHashBits.CopyTo(truncatedHashBytes, 0);

        return BitConverter.ToUInt64(truncatedHashBytes, 0);
    }

感谢您查看此问题。感谢您提供任何反馈!

【问题讨论】:

  • 您是否有必须使用截断字节的高位的规则?你想使用哪种字节序?小的?大的?还是根本不在乎?它是否需要跨 CPU 架构保持一致?
  • 简单地使用BitConverter.ToUInt64(fullHashBits, 0) % (1000000ul * 1000000ul * 100ul)怎么样?它使用原生字节序,因此如果您需要跨 CPU 架构的一致性,您需要 fixed endianness byte[] to integer converter
  • BitConverter.ToUInt64(fullHashBytes.Reverse().ToArray(), 0) &amp; 0x3fffffffffff;
  • @CodesInChaos,感谢您的回复。在这种情况下,我追求的是小端。我不确定我是否理解在这种情况下使用高位和低位的后果。您能对此有所了解吗?
  • @L.B - 感谢您的建议。你的位掩码方法看起来很干净。

标签: c# hash byte bit-manipulation bitarray


【解决方案1】:

在上述 cmets 的帮助下,我制定了以下解决方案:

 public static UInt64 GetTruncatedMd5Hash(string input, int bitLength)
 {
        if (string.IsNullOrWhiteSpace(input)) throw new ArgumentException("input must not be null or whitespace");

        if(bitLength > 64) throw new ArgumentException("bitLength must be <= 64");

        var md5Hash = MD5.Create();

        byte[] fullHashBytes = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

        if(bitLength == 64)
            return BitConverter.ToUInt64(fullHashBytes, 0);

        var bitMask = (1UL << bitLength) - 1UL;

        return BitConverter.ToUInt64(fullHashBytes, 0) & bitMask;
    }

它比我之前尝试做的更紧(也更快)。

【讨论】:

    猜你喜欢
    • 2011-12-15
    • 2011-01-31
    • 2011-10-01
    • 2013-07-20
    • 2017-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-25
    相关资源
    最近更新 更多