高度重复单向哈希算法

时间:2014-04-24 12:02:25

标签: algorithm hash

免责声明这不会用于任何类型的安全

我需要设计/实现一个给定字符串和数字的单向散列函数,它返回一个字符串的散列。方法签名应该与string GetHash(string input, int universe)类似,但有以下限制:

  • universe将大于3,并且永远不会减少(例如,如果使用8作为Universe计算哈希,则不能使用小于8的Universe计算其他哈希)

  • 无论universe参数如何,静态字符串的哈希值应始终相同,例如:
    GetHash(" ABC",3)=> H1,
    GetHash(" ABC",4)=> H1,
    GetHash(" ABC",5)=> H1,
    GetHash(" ABC",6)=> H1

  • 给定N个字符串和固定的universe,生成的不同哈希值的最大数量不能大于universe,例如:
    GetHash(" A",2)=> H1,
    GetHash(" B",2)=> H2,
    GetHash(" C",2)=> H2,
    GetHash(" D",2)=> H2,
    GetHash(" E",2)=> H1,
    GetHash(" F",2)=> H1,
    GetHash(" G",2)=> H2,
    注意增加了宇宙
    GetHash(" A",3)=> H1,
    GetHash(" B",3)=> H2,
    GetHash(" C",3)=> H2,
    GetHash(" D",3)=> H2,
    GetHash(" E",3)=> H1,
    GetHash(" F",3)=> H1,
    GetHash(" G",3)=> H2,
    注意新字符串
    GetHash(" Z",3)=> H1,
    GetHash(" W",3)=> H2,
    GetHash(" Y",3)=> H3,
    GetHash(" T",3)=> H2,
    GetHash(" S",3)=> H1,
    GetHash(" R",3)=> H3,
    GetHash(" Q",3)=> H2

2 个答案:

答案 0 :(得分:1)

唯一的解决方案是为所有字符串和Universe返回相同的哈希值。

考虑到这个要求:

  

给定N个字符串和固定的Universe,生成的不同哈希值的最大数量不能大于Universe。

如果universe为1,则所有字符串的哈希值必须相同。

并且,鉴于此要求:

  

无论Universe参数

,静态字符串的哈希值应始终相同

某些给定字符串的哈希值必须与universe的所有值相同。

此要求实际上使Universe参数过时(超出其下限)。给定一些字符串和一个Universe,它们不会产生与这些字符串和一个较小的Universe不同的哈希值,因为每个单独的字符串需要在所有Universe中具有相同的哈希值。


我假设任何字符串都可以对任何universe参数有效。如果不是这种情况,则场景可能会有所不同(尽管可能需要在问题陈述中包含字符串出现的确切规则)。

这假设universe可以是1.如果universe的下限是2,例如,只需将字符串分成2部分(使用您认为合适的任何条件)并返回一个哈希值对于另一个的另一个哈希(这些哈希也可以是相同的哈希) - 只需适当增加部分的数量,就可以扩展到universe的任何下限。


如果我们忽略了第一个要求,我们或许可以考虑使用任何散列函数将每个字符串散列为一个数字,之后我们可以使用universe来修改(除去除以后的每个字符串) - 这会将返回值限制为[0, universe),因此不会有超过universe个不同的哈希值。

答案 1 :(得分:0)

无法合理地满足您的第一个要求,因为Universe参数值的任何减少都可能需要字符串来更改其哈希值。如果字符串具有universe = 1000的特定哈希值,则无法保证它与universe = 2具有相同的哈希值。满足此要求的唯一方法是将所有输入散列为相同的值:

function sillyHash(input, universe)
  return "42"
end function

您的其他要求可以得到满足。

首先定义Universe的最大允许大小。我建议最多64或128位,但可能更大。

接下来找到一个散列函数,它可以提供最大为所需大小的散列。我通常建议FNV hash,但你可能想要一些不同的东西。你说你不想要加密质量哈希,所以FNV就好了。

现在确定特定Universe参数之上的下一个最大2的幂。运行哈希并将结果截断为该位数。例如,如果您选择universe = 60000,那么这是一个16位数字。例如,您可以运行64位散列并将其截断为16位。如果你有universe = 70000那么你需要17位并相应地截断。如果您想使事情复杂化,那么您可以根据需要调整正在使用的哈希值。

如果您的截断哈希值低于Universe大小,那么您已完成。如果不是,则重新哈希,截断并再次测试。考虑到至少有一半截断的哈希值从一开始就在正确的范围内,它不应该花费两到三次重新哈希来找到一个在范围内的数字。

伪代码:

bitSize <- minimum number of bits to hold universe parameter

temp <- inputString
repeat
  temp <- calcRawHash(temp)
  temp <- truncate(temp, bitSize)
until (temp < universe)

return temp

重复的重新散列是确定性的,因此总是会在0&lt; = hash&lt;的范围内找到相同的数字。 Universe给出相同的输入字符串和Universe大小。