我想为数百万个URL中的每一个创建一个哈希或校验和,以便相同的URL(在清除后(具有相同的哈希/校验和。
如果我生成URL的SHA-1(20字节(或SHA-256散列(32字节(,并通过对散列的每个8字节块进行异或运算将它们存储为大整数(8字节((这里是C#代码示例(,那么它仍然安全吗?我读过一些人说应该没事,但没有找到任何可信的消息来源。
据我所知,[1,5]和[5,1]的XOR是相同的,尽管它们是不同的序列,所以散列XOR技术可能会导致冲突。在这种情况下,像MurMur、FNV或xxHash这样的非加密哈希算法是否更适合我的用例,因为它需要最少的碰撞机会和良好的性能(不一定是最快的(?
简单回答:没有。8字节(64位(的散列将不太可靠来区分"数百万";的URL。
见下表:https://en.wikipedia.org/wiki/Birthday_problem#Probability_table
该表指示了每个给定数量的元素发生碰撞的概率。这里的判断都取决于两件事:你的集合中有多少元素,以及你对";"可靠";。
对于一个打算重复工作的软件,您可能应该评估:
- 您期望出现的元素(URL(的最大数量,特别是当您逐渐添加到集合中时
- 在软件的预期使用寿命内,您的软件将被使用的不同数据集的数量(或次数(
- 您的软件在每个周期/或其使用寿命内的可接受错误率是多少
- 修复一个错误的代价有多高——是内存中的散列&你只需要重新运行,或者你是在DB/文件中持久地收集这些文件,并且它们的回收成本很高
有一些计算器可以帮助计算。我用过这个:https://kevingal.com/apps/collision.html将其切换到"位"模式,而不是桶模式。
评估示例:
- 每年添加1000万个URL
- 软件寿命为20年&一年运行100次,但始终是同一个数据集
- 我们只接受百万分之一的错误机会
- =2亿个URL
- =>通过计算器,74位的散列会给你大约1.1e-6的碰撞机会,但只适用于128位
另一种可能的评估:
- 每个数据集中有5000万个URL或元素
- 软件寿命为20年&每年运行100次,每次使用独立的数据集
- 我们一生只接受一百万分之一的错误机会
- =5000万个URL
- =软件需要运行2000次,使用寿命概率为百万分之一
- =>因此,一次运行中出错的概率需要为~5e-10
- =>通过计算器,一个81位的散列会给你5.2e-10的碰撞机会——只需要128位
结论:保持简单&健壮,使用128位散列
最后几句话:异或既不必要也不可取;只需将散列截断为要使用的字节数。
如果健壮的唯一性很重要,我建议您使用加密级别的哈希,如SHA-256或SHA-1。出于安全目的,SHA-256比SHA-1更强(更能抵抗密码攻击(。这两种算法仍然非常快。