校验和/哈希函数具有可逆属性

时间:2009-04-05 18:41:43

标签: hashcode

我正在寻找具有以下属性的特定哈希码。我不知道任何这样的哈希码,我不知道是否有可能做这样的事情。只是想把它放在那里看看人们说什么。

我有两个数据库(松散使用的术语 - 不要考虑SQL或任何类似的东西),一个主数据库和一个备份数据库。需要保持两个数据库同步并检测数据库何时不同步。不是验证那里的每个数据,而是保留一些可以验证的哈希码。但是这两个数据库不一定共享每一个修改。由于批量处理从主服务器到备份服务器的更改,因此可能会折叠从主服务器到备份的某些修改。

即:假设数据库的当前状态具有元素A-> X,B-> Y和C-> Z.现在B被修改为使得B-> Y1然后B-> Y2。从主服务器发送到备份服务器的唯一更改是B-> Y2。跳过中间体B-> Y1。

现在不是循环遍历每个数据库中的每个元素以验证它们是否匹配,我们宁愿在这两个位置保留元素的运行哈希码,然后只是比较它。哈希码必须计算如下内容:

假设先前的哈希码为hm0:
哈希码hm1 = f(hm0,A-> X,B-> Y,C-> Z)

B现在改变:
哈希码hm2 = f(hm1,B-> Y1)
然后
哈希码hm3 = f(hm2,B-> Y2)

因此master将拥有h3的哈希码。现在备份不会收到修改B-> Y2,所以如果它计算一个正在运行的哈希码,它将是这样的:

哈希码hb1 = f(hb0,A-> X,B-> Y,C-> Z)
哈希码hb2 = f(hb1,B-> Y2)

现在我们希望hb2和hm3匹配,因为数据库的当前状态是相同的。但是大多数(如果不是全部)哈希码都不会以这种方式工作。

那么我们想要的是我们希望首先从散列中“移除”B-> Y的贡献然后“添加”B-> Y1的贡献然后移除B-的贡献> Y1并将B-> Y2的贡献添加到哈希码中。所以我们想要这样的东西:

两个函数f,g:f通过添加新元素的贡献来修改现有的哈希码,而g通过删除元素的贡献来修改现有的哈希码。

主人:
hm1 = f(hm0,A-> X,B-> Y,C-> Z)

当B被修改为B-> Y1:
时 hm2 = g(hm1,B-> Y)
hm3 = f(hm2,B-> Y1)

当B被修改为B-> Y2时:< hm4 = g(hm3,B-> Y1)
hm5 = f(hm4,B-> Y2)

hm5是数据库当前状态的新哈希码(A-> X,B-> Y2,C-> Z)

备份时:
hb1 = f(hb0,A-> X,B-> Y,C-> Z)

当B被修改为B-> Y2时:< hb2 = g(hb1,B-> Y)
hb3 = f(hb2,B-> Y2)

现在hm5和hb3应该匹配,因为两个数据库的当前状态是相同的。

那么:有这样的算法f和g吗?我希望我明白这个问题....谢谢。

2 个答案:

答案 0 :(得分:1)

只需添加和减去您的代码即可。 h(x)是任何散列函数:

hm2 = hm1 + h(B->Y)
hm3 = hm2 + h(B->Y1)
hm4 = hm3 - h(B->Y1) 
hm5 = hm4 + h(B->Y2)

hb2 = hb1 + h(B->Y)
hb3 = hb1 + h(B->Y2)

hm5和hb3相等。

请注意,它不一定要加或减。任何可逆操作都可以工作(理论上乘法/除法也可以工作,但可能会有更多的溢出问题和关于0周围发生的事情的模糊性。)

答案 1 :(得分:0)

嗯。我不确定哈希函数是否完全符合您的要求。但似乎一个类似于Git如何存储其修订版的结构可能会满足您的需求(这是受Monotone如何存储其修订版的启发)。

Git计算存储库中每个文件的SHA-1总和。这些用作blob标识符。然后它有一个树,它将文件名映射到blob ID(以及其他子树,用于子目录)。树的标识符是其SHA-1总和。 (虽然它与你的用法无关,但我不相信,然后通过修订引用树,其中包括作者,日期和一个或多个父修订版本。)

这意味着您在更新每个blob时不必重新计算每个blob的SHA-1总和;你只需重新计算更改的blob的SHA-1,然后重新计算树的SHA-1。

您可以对数据执行相同的操作。计算每个对象的哈希值,并将所有key-&gt;哈希(值)映射放入一个文件中,并计算其哈希值。如果包含key-&gt; hash(value)的文件太大而无法每次重新哈希,你可以将它分成几个部分,并且有一个key-&gt; hash(section),其中每个部分都有键 - &GT;散列(值)。对于大多数情况,一级分支通常应该足够,但如果您确实需要,可以使用这些分支构建树结构。