我很好奇是否有一些简单和/或众所周知的哈希方法具有以下属性:
虽然理论上显然必须存在这样的系统,但实际上有没有呢?
答案 0 :(得分:5)
实践中有很多!
一个简单的解决方案是将输入乘以任何奇数,并取结果的最后32位。那就是:
y = (x * YOUR_ODD_NUMBER) & 0xffffffff;
但是,这确实有一些缺点。它总是将零映射到零,如果你选择像3这样的小数字,那么映射将是相当明显的(类似地,如果你选择像0xffffffff这样的大数字你会得到另一个明显的映射),并且最低有效位不会改变。通常,低位会影响较高位,但高位不会影响较低位。
另一种方法是使用自身的移位版本的独占或数字:
x ^= x >> YOUR_FIRST_SHIFT;
x ^= x << YOUR_SECOND_SHIFT;
y = x ^ (x >> YOUR_THIRD_SHIFT);
您可以根据需要叠加尽可能多的这些微不足道的操作,试图隐藏各个阶段的弱点。即使一个操作本身不是很好,它也可以在更复杂的操作链中有用。例如,异或具有某些常数将避免仅通过乘法将零映射到零的问题,并且移位和异或技术允许低位受高位影响。
如果你看一下PRNGs,你会发现他们中的很多人有一个与他们的州几乎相同的时期。他们通过以你指定的方式置换状态来实现这一点 - 通过1:1映射,其中一个状态与下一个状态之间的关系不是太明显 - 然后它们呈现一些状态(或所有状态)作为伪随机数。一些PRNG和哈希也完成了一个回火阶段,他们执行这些映射中的另一个来隐藏他们自己的一些弱点。
如果你在循环中运行哈希函数,在每次迭代时将y反馈回x,那么你有一个PRNG,你可以用dieharder之类的工具测试它的随机性。
并非所有PRNG都具有理想长周期属性,并且该属性对于良好的散列函数不是必需的,但是一些PRNG算法可以是操作执行的有用思想来源,并且它们具有全面的分析。 / p>
答案 1 :(得分:3)
尝试反转数字的二进制表示形式:
17(10) = 1110(2) -> 10111(reversed, set first bit as indicator) = 23
18(10) = 10010(2) -> 101001 = 41
或将后半部分与下半部分互换:
17(10) = 11|10(2) -> 1011 = 11
18(10) = 100|10(2) -> 10100 = 20
我不确定,但似乎应该适合你。
答案 2 :(得分:2)
一个简单的解决方案是制作一个顺序改变数组。某些加密函数基于此方法。
uint8_t arr[32]={4,7,24,9,15,3,...}; // an order you know
uint32_t orgVal;
uint32_t modVal =0;
uint32_t pos = 1;
for (int i=0; i<32;i++) {
modVal += (orgVal&pos)? (1>>arr[i]):0;
pos*=2;
}
(代码是从头开始制作的,没有IDE或测试;它可能不起作用)
正如评论中所指出的,如果你看一下比特,差异将是最小的:0和1的数量将是相同的。要解决此问题,您可以考虑使用位顺序更改和xor 。然后原始值和结果值之间的差异将更加显着。
答案 3 :(得分:0)
这个很简单,但效率可能不高:
现在您可以通过两种方式应用它,只有那些有表的人才能知道该数字应该是什么。
答案 4 :(得分:0)
一种简单的方法:hash(x) = rotate-shl(x, K1) xor C
您可以结合多个简单操作来获得更多“随机”结果,例如rotate-shl/shr
,bit-reverse
,xor
,not
等等。