【问题标题】:Commutative, accumulator-based function for calculating a digest of multiple hashes可交换的、基于累加器的函数,用于计算多个哈希的摘要
【发布时间】:2011-03-12 14:03:30
【问题描述】:

我正在写一些东西,通过散列文件内容的样本来总结文件系统中的文件。它构造了一个目录和文件树。每个文件条目都有文件内容的哈希值。对于每个目录条目,我想存储目录中所有文件内容的哈希,包括子目录中的文件 - 我将其称为目录内容哈希。

目录内容哈希的棘手之处在于我希望它独立于目录的结构。 IE。如果两个目录包含相同的文件,但使用不同的子目录结构组织,则哈希应该相同。

我能想到的唯一两种方法是:

  1. 计算所有文件内容哈希的串联的 MD5。为了获得所需的哈希属性,我必须列出目录中的所有文件,按它们的哈希排序,连接排序的哈希,然后在连接上运行 MD5。这似乎比我想要的要慢。在计算整个树中的目录内容哈希时,我可以通过使用合并排序非常有效地进行排序,但是我无法绕过在大型输入上计算大量 MD5 哈希。

  2. 使用 XOR 组合文件内容哈希。每个目录只需要对其直接子级的文件内容哈希和目录内容哈希进行异或。这是非常快速和简单的,但不是很耐碰撞。它甚至无法区分包含 1 个文件实例的目录和包含同一文件的三个实例的目录。

如果有一个函数可以使用类似于方法#2 中使用的异或的方式,那就太好了,但更耐碰撞。我认为方法#1对于这种特定情况来说已经足够快了,但是为了探索所有选项/智力好奇心/未来应用程序,我想知道是否有满足描述的功能标题(我对过去几次想要这样的功能有一个模糊的记忆)。

谢谢。

【问题讨论】:

    标签: hash


    【解决方案1】:

    对散列集合进行独立散列排序(本质上是您要查找的内容,不是吗?)

    听起来任何顺序无关的操作(如加法或乘法)都可以为您解决问题。加法的好处是以一种很好的方式溢出。我不记得乘法是否也可以。

    简而言之:添加所有值,忽略溢出,你应该会得到一些有用的东西。如果加法没有足够的抗碰撞能力,任何其他类似的功能都应该可以解决问题。

    【讨论】:

    • 哇,太简单了。我用随机数试了一下。加法是稳定的,所有位都均匀分布......有人知道这是多么耐碰撞吗?谢谢。
    • 顺便说一句,简单的乘法不起作用。我不确定效果是什么,但生成的哈希值并没有均匀分布。想象一下如果任何输入为 0 会发生什么。
    • 你使用了无符号整数吗?是的,零在乘法中被吸收了。为避免吸收,您可以将所有零替换为固定的非零数字。
    • “太简单”是批评还是恭维?无论你走哪条路,你都应该为碰撞做好准备。如果你得到太多,使用另一种方法。我怀疑碰撞率将与原始哈希函数相当(但不等于)。在大多数情况下,Addition 将使用加密哈希函数处理 1 对 3 个文件( (A + A + A) mod MAX+1 必须等于 A)。请注意,您必须进行 X 位数学运算(其中 X 位是哈希函数输出的大小)才能充分利用您的哈希输出(这可能意味着 bignum 数学运算)。
    • 恭维。我继续累加了一个和和一个异或,最后减去了两者。所以哈希是 sum(x1..xn) - xor(x1..xn)
    【解决方案2】:

    因为物品的数量很重要,但顺序不重要;只需对哈希列表进行排序,然后对列表进行哈希处理。

    find . -print0 | xargs -0 sha1sum | cut -c -40 | sort | sha1sum
    

    这将给出与目录排列无关的哈希值类型。

    【讨论】:

      【解决方案3】:

      如果您有可用的 Google guava,它会提供一个实用方法 Hashing.combinedUnordered(),它可以满足您的需求。 (在内部,这是通过将所有哈希相加来实现的。)

      https://code.google.com/p/guava-libraries/wiki/HashingExplained

      【讨论】:

        【解决方案4】:

        我发现这篇文章:https://kevinventullo.com/2018/12/24/hashing-unordered-sets-how-far-will-cleverness-take-you/

        就像@Slartibartfast 所说,加法就是你想要的。这篇文章的有趣之处在于,它证明了无论你做什么“交换”操作,总会有问题元素存在。在加法的情况下,问题元素是哈希为 0 的项目。

        虽然有几种记录方法来定义哈希 迭代顺序为列表和其他容器的函数 保证,围绕最佳实践的讨论似乎较少 用于为无序容器定义散列函数。一明显 方法是简单地将 {(+)} 或 xor {(\oplus)} 的哈希值相加 容器的各个元素。这些方法的缺点 是否存在哈希为 0 的“问题元素”;当这样 元素被插入到任何容器中,该容器的哈希值将 保持不变。有人可能会怀疑这是由于结构化 加法或异或的性质,以及更聪明的哈希选择 无序容器上的函数可以避免这种情况。事实上,在 在文章的结尾,我们将在数学上证明一个命题 粗略地指出,任何用于散列无序的通用方法 容器,可以基于现有的增量更新 哈希,本质上等同于更“明显”的选择之一 因为它具有相同的代数结构,特别是具有 相同的“问题”元素。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-12-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-12
          相关资源
          最近更新 更多