唯一值的哈希 = 唯一哈希吗?

3

理论上,将唯一值哈希化是否会产生唯一值?

假设我有一个带有2个列的DB表:id和code。id是自增整数,code是varchar类型。如果我执行...

$code = sha1($id);

…然后将$code存储在与$id相同的行中。那么我的code列也是唯一的吗?

如果我添加当前时间呢?例如:

$code = sha1($id . time());

感谢您的选择。

不能确定,但我认为你的哈希值不能保证唯一性,因为sha1函数的输出数量是有限的。这意味着由于存在无限数量的潜在密钥,某些不同的密钥在加密时必须映射到相同的值。虽然我不知道sha1算法的内部情况,但我不能告诉你任何介于1和数据库数字列最大值之间的数字是否会哈希到相同的值。也许有人知道这个问题的答案,但我认为使用不同的方法会更好。$code=uniqid() - aw crud
太棒了,谢谢。我不知道uniqid(),我一定会去看看的。 - nebs
4个回答

8
总的来说,答案是否定的。这很容易证明:SHA-1有2^160个不同的输出 - 160位,但有比它更多的输入(例如,有2^320个不同的40字节字符串,它们不能都映射到唯一的输出)。
如果给出足够的子集,则答案可能是肯定的。这取决于精确算法和子集的大小:如果可能的输入数量小于可能的输出数量,则可能(但不保证)。在考虑此问题时,牢记birthday paradox可能会有所帮助:碰撞的概率不会随着输入数量的线性增加而增加。

谢谢。那么获取唯一值的唯一方法就是生成并扫描数据库以检查其是否存在(如果是,则重复)?这基本上是我试图避免在这里做的事情,但我想这是唯一的方法。 - nebs
如果您想保证唯一值,很遗憾,没有其他方法。这也是为什么您不能轻松地反转哈希的原因:我可以告诉您,“1”的SHA-1哈希值为“356a192b7913b04c54574d18c28d46e6395428ab”,但有许多其他值也会生成该哈希值。 - Michael Madsen
我明白了。问题是我可能不需要生成超过1000个唯一值。在这种情况下,所有的值都是唯一的,这样说是否安全? - nebs
1
不行。即使只有两个值,它们哈希到相同值的概率仍为2^160的1分之1。虽然看起来是无限小的,但它仍然比0大,这意味着尽管你的1000个值很可能都哈希到不同的值,但如果没有测试,就不能保证它们不会重复。如果你事先知道可能的值,可以计算出它们的哈希值,把它们放在一个列表中,并按哈希值排序——这将使查找重复项变得容易。 - Michael Madsen
你说得对,谢谢。最终我选择了uniqid,正如RenderIn建议的那样。 - nebs

0

有一种很小的可能性,即两个不同的值会产生相同的哈希值。虽然非常小,但并非不可能。


-1

这取决于哈希算法。但从理论上讲,除非哈希与原始字符串完全相同,否则哈希有可能不是唯一的。

值的哈希是原始值的简化表示。通过删除信息片段来创建哈希,您正在失去使其在域中独特的部分,因此增加了该值不唯一的概率。保证它是唯一的唯一方法是使用原始值本身,这违背了哈希的目的。


"保证数值的唯一性的唯一方法是使用原始值本身" - 显然不是真的! - Martin Smith
@Martin - 请解释一下你的意思,为什么我的说法是不真实的? - Andrew Hare
哈希值不一定要是原始字符串才能保证唯一性。例如,它可以是对原始字符串进行 ROT13 编码后的值,仍然保持唯一。 - Martin Smith

-1

我们必须问这个问题,为什么你想要这样做?如果你的数据库已经提供了一个唯一标识符,为什么还需要生成另一个唯一标识符呢?

你可能还希望考虑到,在 PHP 之外,许多数据库引擎会为你生成 UUID 样式的主键,如果这是你需要的话。

这里的重点是,像 sha1() 这样的哈希算法并不适用于这种类型的工作;它们用于验证两个(潜在非常长的)字符串输入是否相同。与类似但不完全相同的字符串发生冲突的机会非常小,但与非常不同的字符串发生冲突的机会则变得更高。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接