问题描述
过去几天,我一直在研究Rabin指纹。尽管总体思路很简单,但是在理解网上流传的实现时遇到了很多麻烦。特别是它们似乎都是从原始的LBFS paper派生而来的,即滑动窗口是从librabinpoly定义的:
33 static u_int64_t slide8(RabinPoly *rp,unsigned char m) {
34 rp->circbuf_pos++;
35 if (rp->circbuf_pos >= rp->window_size) {
36 rp->circbuf_pos = 0;
37 }
38 unsigned char om = rp->circbuf[rp->circbuf_pos];
39 rp->circbuf[rp->circbuf_pos] = m;
40 return rp->fingerprint = append8 (rp,rp->fingerprint ^ rp->U[om],m);
41 }
42
43 static u_int64_t append8(RabinPoly *rp,u_int64_t p,unsigned char m) {
44 return ((p << 8) | m) ^ rp->T[p >> rp->shift];
45 }
根据初始多项式生成U / T表的位置。在涉及Rabin指纹识别的任何论文中,我都没有看到过讨论这2个表的用法和XOR操作的信息。我的直觉是这与模运算有关,但我不确定。 Git's source code还使用了Rabin指纹识别,但是它们不是动态派生表,而是具有一组预先计算的表。所以我的问题是-这些Xor运算究竟能实现什么功能,并且代码看上去通常与“规范” explanation of the algorithm
完全不同解决方法
“规范解释”使用的滚动哈希不是Rabin指纹。不过,它非常相似。不必太深入抽象代数的杂草,两者的思想是评估从特定ring中的消息派生的多项式,该多项式具有0、1,加法,减法,乘法但不除法(整数mod m为规范解释; GF(2k)为Rabin指纹,也就是说,系数为mod 2的多项式,模为阶k的不可约多项式。
最简单的环是整数mod 2,它具有0、1并定义
+ 0 1 - 0 1 * 0 1
------ ------ ------
0 0 1 0 0 1 0 0 0
1 1 0 1 1 0 0 0 1 .
发生了一件非常有趣的事情:加号和减号具有相同的定义,并且两者都等同于XOR。使用计算机字来表示系数为2的多项式,我们可以使用按位XOR来添加和减去多项式。这就是为什么XOR出现在rp->fingerprint ^ rp->U[om]
中的原因:我们使用U
表从刚离开窗口的字节中减去该项,因为该项只有256种可能性。
XOR的另一种用法((p << 8) | m) ^ rp->T[p >> rp->shift]
在表达式中被不可约多项式修改,即,在规范解释中与m等效。如果我们要通过多项式长除法(大概是如何计算T
表)来执行此操作,则我们会注意到,从红利中减去(在环中)的项由高-仅订购位(p >> rp->shift
)。稍作代数运算之后,我们可以缓存和(在环中),然后从被除数(((p << 8) | m)
中减去(在环中,按位XOR)。
为完整起见,请注意,p << 8
等于多项式乘以x 8 。