【问题标题】:Obtaining a k-wise independent hash function获得一个 k-wise 独立散列函数
【发布时间】:2013-04-23 10:53:45
【问题描述】:

我需要使用属于 k-wise 独立散列函数家族的散列函数。 C、C++ 或 python 中任何库或工具包上的任何指针,它们可以生成一组 k-wise 独立散列函数,我可以从中选择一个函数。

背景:我正在尝试在此处实现此算法:http://researcher.watson.ibm.com/researcher/files/us-dpwoodru/knw10b.pdf 用于不同元素问题。

我看过这个帖子:Generating k pairwise independent hash functions,其中提到使用 Murmur 散列来生成成对独立散列函数。我想知道 k-wise 独立散列函数是否有类似的东西。如果没有可用的,我是否有可能构造这样一组 k-wise 独立哈希函数。

提前致谢。

【问题讨论】:

  • 您可以使用具有k 不同密钥的加密算法。我喜欢 RC4 这样的东西。它不是加密安全的。但出于您的目的,它应该足够接近以避免碰撞。此外,它实施起来既简单又快速。

标签: algorithm hash hash-function


【解决方案1】:

最简单的 k-wise 独立哈希函数(将正整数 x < p 映射到 m 桶之一)只是

p 是一些大的随机素数(261-1 可以) 而ai是一些小于p的随机正整数,a0 > 0。

2-wise 独立散列: h(x) = (ax + b) % p % m

同样,p 是素数,a > 0a,b < p(即a 不能为零,但b 可以是随机选择)

这些公式定义了哈希函数族。如果您在每次运行算法时从相应的族中随机选择一个哈希函数(即,如果您生成随机的 a's 和 b),它们(理论上)就会起作用。

【讨论】:

  • 谢谢,这很有帮助。您能否澄清一下:1)似乎只有当 p 是梅森素数时才会得到双射结果,真的是这样吗? 2) 如果我们只知道 p, m, a, b, h(x),计算原像(原始 x,如果我们只知道输出)是多么困难 - 特别是如果使用的随机多项式高度分解令人沮丧。更好的是,如果你知道一些关于密码学主题的文献 - 我只知道 fi.muni.cz/~xbouda1/teaching/2009/IV111/… 至少可以说已经过时了
【解决方案2】:

没有“k-wise 独立散列函数”这样的东西。但是,存在 k 方向独立的函数族

提醒一下,如果从族中随机选取 h 并且任意选​​取 x_1 .. x_k 和 y_1 .. y_k,则函数族是 k 向独立的,则“对于所有 i,h(x_i ) = y_i" 是 Y^-k,其中 Y 是从中选择 y_i 的共域的大小。

已知有一些函数族对于像 2、3、4 和 5 这样的小 k 是 k 向独立的。对于任意 k,您可能需要使用多项式哈希。请注意,它有两种变体,其中一种甚至不是 2 独立的,因此在实现时要小心。

多项式哈希族可以使用 k 个常量 a_0 到 a_{k-1} 从字段 F 哈希到自身,并由 a_i x^i 之和定义,其中 x 是您要哈希的键。通过让 F 为以素数 p 为模的整数,可以在您的计算机上实现域算术。这可能不太方便,因为通常最好将域和范围设置为uint32_t 等。在这种情况下,您可以使用字段 F_{2^32},您可以使用 Z_2 上的多项式乘法,然后除以该字段中的不可约多项式。否则,您可以在 Z_p 中操作,其中 p 大于 2^32(或 64)并取多项式模 2^32 的结果,我认为。这几乎是k-wise独立的,但有时这足以让分析通过。重新分析 KNW 算法来改变它的哈希族并不容易。

要生成 k-wise 独立族的成员,请使用您最喜欢的随机数生成器随机选择函数。在多项式哈希的情况下,这意味着选择上面提到的as。 /dev/random 应该足够了。

您指向的论文“An Optimal Algorithm for the Distinct Elements Problem”是一篇不错的论文,已被多次引用。然而,它并不容易实现,而且它可能比 HyperLogLog 更慢甚至占用更多空间,这是由于 big-O 符号中的隐藏常量。许多论文已经注意到该算法的复杂性,甚至称其与 HyperLogLog 相比是不可行的。如果您想为不同元素的数量实现估计器,您可以从早期的算法开始。如果您的目标是教育,那么那里有很多复杂性。如果您的目标是实用性,那么您也希望远离 KNW,因为仅仅为了让 HyperLogLog 不那么实用可能需要做很多工作。

作为另一条建议,如果您想了解和理解此算法或其他使用散列的随机算法,您可能应该忽略“仅使用 Murmur 散列”或“从 xxhash 中选择 k 个值”的建议。 Murmur/xx 在实践中可能没问题,但它们不是 k-wise 独立的族,并且此页面上的一些建议甚至在语义上都不是格式正确的。例如,“如果你需要 k 个不同的哈希,只需重复使用相同的算法 k 次,使用 k 个不同的种子”与 k-wise 独立族无关。对于您要实现的此算法,您最终将应用散列函数任意次数。您不需要“k 个不同的散列”,您需要 n 个不同的散列值,这些散列值首先从与 k 无关的散列系列中随机选取,然后将所选函数应用于作为此类算法输入的流式密钥。

【讨论】:

  • 感谢您的精彩解释。您能否推荐一些快速且优化的库,这些库可以从 k [k]。我有一个关键应用程序,我只是从 1-k 生成 n 个随机数,这对于我的目的来说似乎很慢。谢谢
  • 嗨@jbapple,你有这个答案的好来源吗?
  • CLRS 应该可以,我相信。
【解决方案3】:

这是众多解决方案之一,但您可以使用例如以下开源哈希算法: https://github.com/Cyan4973/xxHash

然后,要生成不同的哈希,您只需提供不同的种子。

考虑主函数声明:

unsigned int XXH32 (const void* input, int len, unsigned int seed);

因此,如果您需要 k 个不同的哈希值,只需将相同的算法重复使用 k 次,并使用 k 个不同的种子。

【讨论】:

  • :非常感谢。只是需要澄清一下:如果我用 k 个随机种子生成 k 个不同的哈希函数,这是否意味着这些函数是 k-wise 独立的? (或至少在统计上接近 k-wise 独立)。我已经在使用 pyhash 库并使用具有不同种子的 murmur32 哈希函数。
  • 这完全取决于哈希算法的质量。 MurmurHash 和以上 xxHash 都已经用 SMHasher 进行了彻底的测试,证明使用不同种子的 2 个结果之间没有位依赖性。这个世界上没有什么是完美的,但这两个具有接近完美的随机分布。
  • 请注意,xxHash 不是 k 独立的,因此对于某些键集它可能会失败。如果您负担得起,最好使用下面的多项式哈希,该算法已被证明有效。
【解决方案4】:

只需使用良好的非加密哈希函数即可。这个建议可能会让我在理论计算机科学领域的同事中不受欢迎,但请考虑一下你的对手。

  1. 自然。是的,也许它会遇到导致您的哈希函数表现不佳的小部分输入,但是还有很多其他方法可以解决 k-wise 独立哈希族无法解决的问题(例如,随机数选择散列函数的生成器做得不好,有错误等),所以无论如何你都需要端到端测试。

  2. 不经意的对手。这就是理论所假设的。不经意的对手无法查看您的随机位。如果他们在现实生活中这么好!

  3. 不可忽视的对手。随机性是没有意义的。使用二叉树。

【讨论】:

  • 我不知道该怎么回答这个问题。问题是“我需要一个散列函数”,响应是“只使用一个散列函数”???
  • @BenFulton 问题是“我需要一个 k 向独立散列函数”,我的回答是“不,你不需要;k 向独立性是一个在理论上比在练习”。
  • 我的理解是,根据“On the k-independence required by linear probing and minwise independence”,线性探测实际上需要5-wise independence才能在实践中很好地工作
【解决方案5】:

我不是 100% 确定您所说的“k 向独立散列函数”是什么意思,但是您可以通过提出两个散列函数,然后使用它们的线性组合来获得 k 个不同的散列函数。

我的布隆过滤器模块中有一个例子:http://stromberg.dnsalias.org/svn/bloom-filter/trunk/bloom_filter_mod.py忽略get_bitno_seed_rnd函数,看看hash1、hash2和get_bitno_lin_comb

【讨论】:

  • 这不正是您不想想要为布隆过滤器做的吗?我认为布隆过滤器的效率取决于使用 k 个独立的哈希函数。散列函数的线性组合是按定义不独立的。
  • 我相信将线性组合与布隆过滤器一起使用是很常见的。见stackoverflow.com/questions/11954086/…。此外,我使用的布隆过滤器实现使用线性组合,并且单元测试确认值的分布非常好。此外,至少在 python 中,使用随机数生成器的种子效果很差——这就是我所取代的。单元测试证实了这一点。
  • 同意,我从其他人那里听到了同样的话,他们已经验证了布隆过滤器中的误报率,该过滤器非常像你的那样结合了哈希函数。我只是无法理解为什么会这样。
  • FWIW,它与 Knuth 对线性同余伪随机数的描述并没有太大的不同——它当然很好地分散了值。对于第 k 个哈希函数,您执行 hash1 + k*hash2 mod n 其中 n 是过滤器中的位数,并且 hash1 和 hash2 是 0
  • @ChrisWarth 对于为什么使用两个函数可以的直观解释是,两个数字极不可能产生相同的两个“基本”哈希值。更常见的情况是两个“基本”哈希相加并(在修改它们之后)映射到哈希映射中的相同值。渐近地,第一种情况变得可以忽略不计。第二种情况与常规布隆过滤器误报发生的机会相同。阅读 Kirsch 和 Mitzenmacher 的论文《Less Hashing, Same Performance》了解正确的数学。
猜你喜欢
  • 2012-08-20
  • 1970-01-01
  • 2018-03-09
  • 2018-12-29
  • 1970-01-01
  • 2013-12-26
  • 1970-01-01
  • 1970-01-01
  • 2017-03-27
相关资源
最近更新 更多