为独立于平台的字符串生成哈希代码

本文关键字:字符串 哈希 代码 于平台 独立 平台 | 更新日期: 2023-09-27 18:24:00

我们有一个

  • 在字符串上生成哈希代码
  • 将该哈希代码与相关数据一起保存到数据库中
  • 稍后,它使用字符串哈希代码查询DB以检索数据

这显然是一个错误,因为字符串返回了值。GetHashCode()不同于.NET版本和体系结构(32/64位)。更复杂的是,我们离一个版本太近了,无法重构我们的应用程序,从而停止序列化哈希代码,而只对字符串进行查询。我们现在想做的是想出一个快速而肮脏的解决方案,然后重构代码以正确的方式进行。

快速而肮脏的修复方法似乎是创建一个跨体系结构一致的静态GetInvariantHashCode(字符串)辅助方法。

可以提出一种在32位和64位架构上等效的字符串上生成哈希码的算法吗?

更多注意事项:

  • 我知道HashCodes不是唯一的。如果一个hashcode在两个不同的字符串上返回匹配,我们会对结果进行后处理,以找到完全匹配的字符串。它不用作主键
  • 我相信架构师的意图是通过查询long而不是NVarChar来加快搜索速度

为独立于平台的字符串生成哈希代码

我知道HashCodes不是唯一的。如果一个hashcode在两个不同的字符串上返回匹配,我们会对结果进行后处理,以找到完全匹配的字符串。它不用作主键。

我相信架构师的意图是通过查询long而不是NVarChar 来加快搜索速度

然后让数据库为您的字符串编制索引

听着,我不知道你的域有多大,但如果它有任何合适的大小,你会很快发生碰撞,可能性很高。这是很多人的生日问题,与生日的数量有关。你会发生碰撞,失去任何你可能认为通过一开始就不只是索引字符串而获得的速度增益。

不管怎样,如果您离发布还有几天的时间,并且您真的需要一个跨平台的不变哈希代码,那么您就不需要我们了。有一些非常愚蠢、非常快速的散列代码实现可以使用。见鬼,你一眨眼就能想出一个:

string s = "Hello, world!";
int hash = 17;
foreach(char c in s) {
    unchecked { hash = hash * 23 + c.GetHashCode(); } 
}

或者你可以使用老的伯恩斯坦散列。他们会给你带来你想要的性能提升吗?我不知道,它们不是用来做这个的。它们是用来平衡哈希表的。你没有平衡哈希表。你用错了概念。

编辑(以下内容是在使用新的显著信息编辑问题之前编写的)

理论上,如果没有对输入空间的某种限制,你根本无法做到这一点。您的问题比String.GetHashCode在不同平台之间的差异严重得多。

CCD_ 2有很多实例。事实上,实例比Int32的实例多得多。所以,由于piegonhole原理,你会有碰撞。你无法避免这一点:你的string是鸽子,你的Int32哈希码是piegonhole,有太多的鸽子无法进入鸽子洞,而一些鸽子洞却无法获得多只鸽子。由于冲突问题,不能将哈希码用作字符串的唯一键。它不起作用。时期

要使当前提出的设计有效(使用Int32作为string实例的标识符),唯一的方法是将字符串的输入空间限制为大小小于或等于Int32 s的大小。即便如此,您也很难想出一种算法,以独特的方式将string s的输入空间映射到Int32

即使你试图通过使用SHA-512或其他什么来增加鸽子洞的数量,你仍然有可能发生碰撞。我怀疑你之前在设计时是否考虑过这种可能性;该设计路径是DOA。无论如何,这不是SHA-512的用途,它不用于消息的唯一标识。这只是为了降低伪造信息的可能性。

更复杂的是,我们离一个版本太近了,无法重构我们的应用程序,从而停止序列化哈希代码,而只对字符串进行查询。

那么,你还有大量的工作要做。很抱歉你这么晚才发现这个。

我注意到String.GetHashCode:的文档

GetHashCode的行为取决于它的实现,它可能会从公共语言运行库的一个版本更改为另一个版本。发生这种情况的一个原因是为了提高GetHashCode的性能。

和来自Object.GetHashCode:

GetHashCode方法适用于哈希算法和数据结构(如哈希表)。

哈希代码用于平衡哈希表。它们不是用来识别物体的。如果你把这个概念用于它的用途,你本可以更早地发现这一点。

您应该只使用SHA512。

请注意,散列不是(也不可能是)唯一的
如果你需要它是唯一的,只需使用身份函数作为你的散列。

您可以使用其中一个托管加密类(如SHA512Managed)通过ComputeHash计算独立于平台的哈希。这将需要将字符串转换为字节数组(即:使用Encoding.GetBytes或其他方法),速度较慢,但要保持一致。

也就是说,散列不能保证是唯一的,并且实际上不是数据库中唯一性的适当机制。使用哈希存储数据可能会导致数据丢失,因为第一次哈希冲突会覆盖旧数据(或丢弃新数据)。