如果安全不是问题,我认为你描述的内容
不是哈希函数。哈希函数是一种单向函数,意味着计算哈希很容易,但还原哈希很“困难”,理想情况下是不可能的。
相反,你的要求描述了一个
单射函数。对于你定义域X中的任何x1、x2,以下条件成立:
For all x1, x2 element of X, x1 != x2 => f(x1) != f(x2)
f(x)=x是这样一个函数,f(x)=x²不是。简单来说:你希望在输入不同的情况下得到不同的结果,在输入相同的情况下得到相同的结果。对于安全哈希来说也是如此,但它们还提供了单向特性,例如只通过f(x)很难(容易地)找到x等属性。据我所知,您不需要这些安全特性。
显然,从字符串到浮点数的这种可逆映射将由将“字符串字节”解释为“浮点字节”来给出,即您以后以不同的方式解释字节(想想C:
unsigned char *bytes = "...";
double d = (double)bytes;
但是,这种方法也有缺点——浮点数具有最大精度,所以如果你的字符串太长,就会遇到溢出情况(在32位机器上,浮点数内部表示为
double
值,即8个字节)。因此,对于几乎任何用例来说,空间都不足。即使先对字符串进行MD5处理,也无法解决问题——MD5输出已经是16个字节长了。
因此,这可能是一个真正的问题,具体取决于您的确切要求。虽然MD5(或任何其他哈希)会足够地混淆输入,使其尽可能随机,但您仍然将可能值的范围从16个字节削减到实际上的8个字节。(注意:在保留随机性方面,将随机的16字节输出截断为8字节通常被认为是“安全”的。椭圆曲线加密也采用了类似的方法。但据我所知,没有人真正证明过它,但也没有人能证明相反)。因此,在受限的Float范围内发生碰撞的可能性更大。根据生日悖论,找到碰撞需要sqrt(有限范围内的值数量)次尝试。对于MD5,这是2^64,但对于您的方案,只有2^32。这仍然非常非常不可能产生碰撞。这可能类似于同时中彩票和被闪电击中的几率。如果您可以接受这种微小的可能性,请继续使用:
def string_to_float(str)
Digest::MD5.new.digest(str).unpack('D')
end
如果唯一性是绝对优先考虑的话,我建议从浮点数转换为整数。Ruby支持大整数而不受
long
值的内部限制(那就是Fixnum的本质)。因此,任何任意哈希输出都可以表示为一个大整数。