可逆的“哈希”函数,从64位整数到64位整数

时间:2015-12-25 18:46:11

标签: algorithm combinations

我需要的是一个可逆函数,它将 long (64位整数)转换为另一个 long 数字,其方式是:对于用户而言似乎是“随机的”(但实际上是确定性的),因此3个后续数字被转换为3个完全不同的数字。

很容易做到这一点而不是可逆的,但事实证明这部分非常困难。

基本上它与Reversible hash function?的问题相同,但我需要超过2 ^ 32个不同的值。

有什么想法吗?

PS:我将用Java编写它,但问题本身非常通用。

4 个答案:

答案 0 :(得分:8)

这些是分组密码的基本要求,通常使用Feistel结构实现:https://en.wikipedia.org/wiki/Feistel_cipher

  1. 创建低32位的散列并将其异或为高32位
  2. 交换低位和高位32位
  3. 重复几次。

答案 1 :(得分:3)

您可以使用任何64位分组密码(例如,DES),并使用加密进行"散列",并解密"反向散列"。

答案 2 :(得分:0)

如果您不关心安全性,并且您只需要在视觉上随机化数字,那么一个非常快速的解决方案就是在代码中使用带有固定密钥的简单XOR。为了得到它,再次使用这个秘密'键。

如果您对安全性感兴趣,但没有空间限制,则可以使用更大的键(例如滑动XOR)或甚至OTPHere是OTP的Java示例。

我还应该强调以下两种情况,即使用某些对称加密算法(即使是简单的XOR或OTP)已经提出的解决方案可能无法按预期工作。

  1. 如果我们需要保持号码的标志
  2. 如果我们需要保持数字的大小(例如我有一个5位数字,我想显示其可逆随机5位数版本(或至少接近其大小(4-6))
  3. 为了支持上述要求,基于策略的修改后的XOR / OTP(仅适用于所需的位)可能是一个很好的选择。

答案 3 :(得分:0)

static long GMULL = 0x9E3779B97F4A7C15L;
static long GDIVL = 0xF1DE83E19937733DL;
static long GADDL = 0x0123456789ABCDEFL;
public static long golden64fwd(long key) {
    key *= GMULL;
    key += GADDL;
    return key;
}

public static long golden64rev(long key) {
    key -= GADDL;
    key *= GDIVL;
    return key;
}

static int GMULI = 0x9E3779B9;
static int GDIVI = 0x144CBC89;
static int GADDI = 0x01234567;
public static int golden32fwd(int key) {
    key *= GMULL;
    key += GADDL;
    return key;        
}

public static int golden32rev(int key) {
    key -= GADDI;
    key *= GDIVI;
    return key;        
}

因此就哈希属性而言,它至多是平均值。 GMUL [I,N]是64位和32位的近似黄金比例。 GDIV [I,N]是各自的乘法逆变量2 ^大小。 GADD [I,N]是一个奇数。有些数字是连续的,它们的“散列”值也非常接近。但我怀疑连续三个。