ハッシュ値が衝突する確率について with 誕生日攻撃
はじめに
過去に書いたネタ記事が最近バズっていた。
なので、ある特定のハッシュ値と衝突する確率を求めただけになっていたが、コメントで「沢山ハッシュ値を生成して、その中で衝突する場合はどうなるの?」ともらった。
そりゃ気になるよね。僕も気になる。
...求めてみよう。
今回考えること
SHA256 によってハッシュ値を取ることを想定する。この際、 SHA256 が取る値は一様にランダムとする。
衝突の確率
衝突の確率は、誕生日攻撃と呼ばれるもので求められている。
を使えば簡単に求められる。
.
.
.
と、思うじゃん?
近似式を使う時、近似できる条件と、近似の精度を気にする必要がある。
近似確率
そもそも、その近似式の出所は、英語版の誕生日攻撃に引用元が書かれていた。
その論文の p273-274 の "THE BIRTHDAY PROBLEM" という付録Aに導出過程が記されている。
そこを読む限り、近似できる条件に
という評価ができる。また、
という評価もできる。
実際に求めてみる
上界と下界が分かったので、実際に求めみる。
wiki の表によると、256bit で
import math
def getProbableRange(h, n):
upperBound = n * (n - 1) / (2 * h)
lowerBound1 = 1 - math.exp(-n * (n- 1) / (2 * h))
lowerBound2 = 0
if n * n <= 2 * h:
lowerBound2 = 0.3 * n * (n - 1) / h
lowerBound = lowerBound1 if lowerBound1 > lowerBound2 else lowerBound2
return (lowerBound, upperBound)
h = 2 ** 256
n = 4.8 * 10 ** 29
(lowerBound, upperBound) = getProbableRange(h, n)
print("n = 4.8 * 10 ** 29")
print(f"{lowerBound} < p < {upperBound}")
n = 4.9 * 10 ** 29
(lowerBound, upperBound) = getProbableRange(h, n)
print("n = 4.9 * 10 ** 29")
print(f"{lowerBound} < p < {upperBound}")
結果は下記のようになった。wiki の表は上界の値を元に作成されていそう。近似の精度もそれなりにありそう。
(本来はいろんな値を見るべきだが今回は省略)
n = 4.8 * 10 ** 29
5.969319705281278e-19 < p < 9.948866175468797e-19
n = 4.9 * 10 ** 29
6.220632210234529e-19 < p < 1.0367720350390882e-18
確率から個数を求める
上では
def getMaxNumberUnderProbabilty(h, p):
f = lambda h, p, a, b: a if b - a <= 1 else f(h, p, (a + b) // 2, b) if getProbableRange(h, (a + b) // 2)[1] < p else f(h, p, a, (a + b) // 2)
return f(h, p, 1, h)
h = 2 ** 256
p = 10 ** -15
n = getMaxNumberUnderProbabilty(h, p)
print(f"{n:.2E}")
実行結果は下記。
1.52E+31
wiki の表の 256bit と
確率の比較
今回は前回の表を元に、SHA256のハッシュ値を
事象 | 10の累乗表記 | 同時生成数 |
---|---|---|
ロイヤルストレートフラッシュ | ||
天和 | ||
2択20問のテストででたらめ回答で0点 | ||
宝くじ一等 | ||
何もせず6Vが生まれる(ポケモンの話) | ||
天和四暗刻大四喜字一色 | ||
センター国語(2020)で適当回答で満点 | ||
40人クラスの席替えが席替えにならない | ||
54枚のトランプが購入時の並び順になる | ||
100個のサイコロ振ってゾロ目 | ||
ある1つの SHA256 が衝突する |
サイコロ振りたい
追加で実用的な面から衝突する確率を求めてみる。
下記の仮定の元で、全世界の人が一生の間ハッシュ値を生成し続ける。
- 世界人口: 100億人
- 平均寿命: 100年
- 1秒間の生成数: 100個
- 1年: 365日(31536000秒)
つまり
2.5756705139739875e-35 < p < 4.2927841899566463e-35
の間になる。一方、
実際にサイコロ45個振ってみた
前回よりもインパクトが減るが振ってみる。
私を振ってんじゃないよバカ
振っていいわけがないでしょう
という歌が聞こえてくるがお構いなし。
45個のサイコロを準備した。
それを手にもって振る!
その結果...
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
全部ピンじゃねぇかっ・・・!
.
.
.
.
.
.
.
.
.
.
.
まぁ、そんなわけないよね。
あとがき
同じネタを繰り返すことを天丼という。
宣伝
麻雀の待ちについて研究した記事。
Discussion