【问题标题】:Looking for a C# hash faster then MD5 or SHA256寻找比 MD5 或 SHA256 更快的 C# 哈希
【发布时间】:2013-06-26 05:30:58
【问题描述】:

我正在尝试找到可能比 SHA256 更快的东西。我有超过 10 亿条记录需要散列并验证它们是否唯一。我目前正在通过 MD5 运行它,它看起来非常快,然后通过 sha256 来避免碰撞。按这个顺序运行它们似乎给了我一点性能提升,但我仍然需要它更快。我正在寻找在 c# 中完成的一些哈希的名称或示例或一些伪代码,以便我可以在 c# 中重新创建它。

【问题讨论】:

  • 如果记录都非常正常,我会说 MD5 适合您的需求。您只会从专门制作的奇怪输入中获得碰撞,而不是来自非常相似但略有不同的记录。
  • I am currently running it through an MD5 which seems pretty fast then through the sha256 to avoid collisions 只是为了确定,您正在散列到 MD5,那么如果两条记录具有相同的散列,您检查 sha256 以避免冲突?如果是这样,您可以尝试用 CRC 替换 MD5,这应该会更快(但显然会产生更多冲突)
  • 我只是让它们同时运行,以尝试进一步减少冲突
  • 如果 MD5 值发生冲突,肯定会导致 SHA-256 输出发生冲突吗?还是我误解了您如何使用 SHA-256?
  • SHA-2(MD5(x)) 是个坏主意。在您的情况下,与 MD5(x) 相比没有优势。

标签: c# hash cryptography md5 sha256


【解决方案1】:

这里的答案中有很多可疑的信息。你用cryptography 标记了你的问题,只提到了加密哈希函数,但听起来你并不真的需要加密安全,特别是因为你说:

我有超过 10 亿条记录需要散列并验证它们是否唯一。

cryptographic hash function 有四个属性:

  • 很容易计算任何给定消息的哈希值
  • 生成具有给定哈希的消息是不可行的
  • 在不更改哈希的情况下修改消息是不可行的
  • 不可能找到两条具有相同哈希的不同消息。

您实际上只对第一质量感兴趣,唯一性是一个较小规模的要求,仅与密码安全性的其他三个属性部分相关。

你为什么在乎?

加密安全存在开销。您不需要它,而且您对速度感兴趣,那么为什么不跳过它呢?毫无疑问,MD5 和 SHA 系列的哈希宽度足以满足您的目的。

查看维基百科上的hash functions 列表,或查看normal hash functions 上的文章。更重要的是,内置的 .NET 散列函数有什么问题?您是否尝试过遵循Object.GetHashCode() 方法?该 MSDN 参考对使用哈希函数有很多话要说。你对你正在散列的数据没有说太多,所以很难说输出在你的对象之间是否是唯一的。您如何将对象输入 MD5 哈希器?我想你正在接受它的二进制表示。可以使用类似的方法来使用内置的非加密哈希函数。

您可能会担心内置哈希函数的唯一性。它们只返回一个常规的 int,即 2^32,仅比您正在使用的数据集大 4 倍左右。但是,您始终需要为哈希函数制定备份计划。碰撞是不可行的,并非不可能。标准回退是执行更昂贵的比较,通常是参考比较和逐字段值比较。

如果您不准备对哈希输出进行精确比较,那么您基本上是在倒计时,直到得到误报。这对你来说可能没什么大不了:只有你可以判断有什么缺点。

此外,执行另一个哈希函数计算可能并不比直接比较快多少。你最好在所有方面都选择确定的事情并进行冗长的直接比较。

另一种常见的防冲突技术是使用多个键。因此,如果您的数据点有几个大的子组件,您可以独立地进行散列和比较。如果它有一些大的和一些小的组件(比如一些简单的数字类型),你散列大的并直接比较小的。如果他们有一些易于取序的数据(比如字符串的长度或某些容器的大小),您可以对这些位进行直接比较。

如果这不适合您,请查看 wiki 上列出的其他哈希函数的实现。这是一个pretty good reference for MurmerHash3,它可以计算 32 位或 128 位哈希值。列表中还有其他散列函数也具有长散列宽度,并且还有可用的 C# 库。但正如该参考资料所指出的,Murmurhash 比 MD5 和 SHA 函数快得多,尽管它与我上面提到的 Object.GetHashCode 方法没有直接比较。

【讨论】:

  • 使用 256 位加密哈希,我不会担心备份计划。意外碰撞的可能性远小于随机硬件错误的可能性(例如,您的 RAM 中的一点翻转)。 - “验证:对数学不好的人征税”
  • @CodesInChaos 你说的有些道理。但是,当您只是使用散列函数进行快速唯一性检查时,使用更短的散列宽度可能会更快(运行;编码和维护明显更慢),没有加密安全性,并由直接比较支持。既然这就是问题的重点,那我就是这样制定答案的。这都是权衡的问题:哈希有多慢,直接比较有多慢,预期的碰撞率是多少,碰撞的后果是什么等等等等。
【解决方案2】:

做点不一样的怎么样?

对每条记录使用简单的散列函数,就像将记录插入散列表时使用的那样,可能将每条记录映射到 32 位 INT。然后,如果发生哈希冲突,则比较冲突记录的唯一性。

【讨论】:

  • +1 这基本上意味着你指望这样一个事实,即如果一个非常简单(和糟糕)的哈希不同,那么一个非常好的哈希肯定会不同。没有误报。
【解决方案3】:

您可以使用 MD5,如果遇到冲突记录,您可以使用 SHA256 甚至 SHA128 进行检查。

【讨论】:

    【解决方案4】:

    您是否使用 sha256 检查每条记录?您应该只需要检查您有 md5 冲突的记录,即使使用 md5 也应该很少见。此时,当您只是比较重复项时,将原始记录与原始记录进行比较可能会更快,因为比较将返回第一个差异。

    【讨论】:

    • 拥有超过 10 亿条记录,我发生碰撞的几率有多大?在哪里可以找到?
    • 大约每 2^64 条记录发生一次冲突。发生碰撞就像中了彩票……但你买了足够多的票,它可能会发生。可能是。好吧,可能不会,但你仍然需要做好准备。 stackoverflow.com/questions/8852668/…
    • 这是一个生日悖论问题。 MD5 密钥(天数)为 128 位,因此有 2^128 个。使用1e9 记录(生日),发生碰撞的大致机会是1 - exp(-1e18 / 2^129) ~= 1.5e-21。碰撞的可能性很低,但比天真的预期要高得多(此评论的初始版本包含一个错误;我很抱歉)。有关更多详细信息,请参阅此answer
    【解决方案5】:

    您甚至可以执行类似采用 MD5 的操作,如果发生碰撞,请在两个值中添加一些额外数据(相同)并再次采用 MD5。如果它们不同,则 2 极不可能再次发生碰撞。因此,与其在碰撞后执行 SHA,不如在 MD5 中再次添加一些应该更快的东西。

    【讨论】:

      【解决方案6】:

      从您提出问题的方式来看,您似乎不需要安全级哈希算法。如果你已经传达了你想要完成的所有主要要求,你可能根本不需要哈希算法。

      如果您正在构造一个名为 unique 的方法,当且仅当两行唯一时返回布尔值 true,您可以通过按此顺序使用以下三行特征来提高速度并保持可靠性。

      • 长度(如果它们不是固定长度的记录)
      • 校验和
      • 实际值

      如果记录长度是可变的,第一个可能已经知道。秒可以在存储的时候快速计算出来。拥有 10 亿条记录,即使您使用安全级哈希算法(无论如何您说它太慢),您也必须考虑发生冲突的可能性。因此,当校验和匹配时,如果校验和中有足够数量的位,这种情况很少见,您将不得不涵盖逐字节比较实际值的情况。

      【讨论】:

        猜你喜欢
        • 2016-01-03
        • 1970-01-01
        • 2010-12-26
        • 2020-12-08
        • 1970-01-01
        • 1970-01-01
        • 2017-05-30
        • 2020-06-07
        相关资源
        最近更新 更多