SHA 如何为 git 中的大文件生成唯一代码

How does SHA generate unique codes for big files in git

使用 Git 我不明白如何使用 SHA 生成 40 个十六进制数字代码,然后可以将其映射到任何可能有数百行长的文件。

按照我的想法,可以说字符串“1”-> 00...01,字符串“2”-> 00..02,字符串 'a34ed..fc'-> a34ed..fc 等所以散列图正在返回自己然后很明显所有散列码都很快用完并且任何长度为 41 个字符的字符串都将重复使用其中一个代码。

我也知道 SHA 并不能保证它永远是唯一的,但我不知道它是如何接近有用的。

SHA-1 散列的长度为 160 位。这给你 2160,或者恰好是

1,461,501,637,330,902,918,203,684,832,716,283,019,655,932,542,976

可能的哈希值。

假设散列值或多或少是不可预测的,那么两个文件意外具有相同散列值的可能性微乎其微,以至于不值得担心。

引用 Scott Chacon 的书 "Pro Git":

However, you should be aware of how ridiculously unlikely this scenario is. The SHA–1 digest is 20 bytes or 160 bits. The number of randomly hashed objects needed to ensure a 50% probability of a single collision is about 280.

...

Here’s an example to give you an idea of what it would take to get a SHA–1 collision. If all 6.5 billion humans on Earth were programming, and every second, each one was producing code that was the equivalent of the entire Linux kernel history (1 million Git objects) and pushing it into one enormous Git repository, it would take 5 years until that repository contained enough objects to have a 50% probability of a single SHA–1 object collision. A higher probability exists that every member of your programming team will be attacked and killed by wolves in unrelated incidents on the same night.

确实必须有两个 21 字节的文件具有相同的 SHA-1 哈希值(因为有 2168 个这样的文件并且只有 2 160 个可能的 SHA-1 哈希)。 从未发现过此类文件。

更新: 截至 2017 年 2 月,已生成两个具有相同 SHA-1 校验和的不同 PDF 文件,使用的技术比暴力破解快 100,000 倍以上攻击。详情在这里:https://security.googleblog.com/2017/02/announcing-first-sha1-collision.html

Linux Torvalds(Git 的作者)在这里发布了一个(初步)回复:http://marc.info/?l=git&m=148787047422954

看评论,OP最初的误解似乎是假设SHA-1哈希可以用来确定文件的内容。它不能。 Git 使用 SHA-1 必须构造文件或其他对象的 name。该文件本身存储在 .git/objects 目录下的某处。例如,一个散列为

的文件
ff5a5eff8c90da934937165c9d0e9f96f9ecaf75

可能存储在

.git/objects/ff/5a5eff8c90da934937165c9d0e9f96f9ecaf75

-- 该文件可以任意大。 (当然,这不是那么简单;git 玩了很多技巧来组合相似的文件并以其他方式压缩数据。)感谢 Patrick Schlüter 的评论。

事实上,我对你的称呼"margin of safety"决定了你可以存储多少对象。

广泛引用的 "about 280" 数字是您有大约 50% 的哈希冲突机会的点。为了将几率保持在 1018 中的 1 以内,存储库中不同对象的数量不应超过大约 1.7 千万亿(1.71x1015 ).

(我为我正在写的一本书做了一些数学计算;我还没有让真正的数学家检查过它,但是当我 运行 将相同类型的数字与其他哈希大小进行对比时,我的输出与 those on Wikipedia 一致,无论其价值如何。:-) )

编辑补充:这是近似公式。令 r 为散列函数的基数(因此 r 对于 SHA-1 为 2160)并且 U 是所需的 probability-of-uniqueness(所以 U 是 0.5 对于通常的“50% 的安全机会,50% 的碰撞机会" 统计。哈希输入的最大数量为:

(1 + sqrt(1 + 8r ln (1 / U)) / 2

1 / .5 的自然对数大约是 0.693,所以我们有大约 sqrt(4r)/2,这当然只是大约 sqrt(r)。因此,对于 k 位哈希,“50% 的唯一性概率”发生在大约 k/2 哈希之后。

要查看(大概)我是如何得到我的号码的——在 1015 个对象附近——令 U = 1 - 10 -18。这个数的自然对数基本就是原来的10-18,也就是说我们敲掉了大部分260的运行ge r,还剩约2100。其平方根约为 250,即约为 1015.

错误是没有使用SHA码生成任何文件的内容,内容由Git单独存储。 SHA 代码仅用作提交的密钥。提交不能只让键从 1 开始编号并递增的原因是因为 Git 不同的人可以在同一项目的不同分支上工作,在彼此不知情的情况下进行提交。当这些合并在一起时,我们仍然需要提交来拥有唯一的键。使密钥绝对唯一的最佳方法是使用 SHA 之类的东西,它创建一个唯一的代码,正如其他人所解释的那样,获得相同密钥的可能性几乎为零。