免责声明这不会用于任何类型的安全
我需要设计/实现一个给定字符串和数字的单向散列函数,它返回一个字符串的散列。方法签名应该与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
答案 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大小。