今天不知道在什么地方看到這個東西,感覺挺有意思的,故作文以記之(
當 \(base\) 為偶數時,隨便造一個長度 \(>64\) 的字符串,只要它們后 \(64\) 位相同那么倆字符串的哈希值就相同,直接就卡掉了。
當 \(base\) 為奇數時,對於一個只有 \(\text{a}\) 和 \(\text{b}\) 組成的字符串 \(s\),我們定義 \(\bar{s}\) 為將 \(s\) 中所有 \(\text{a}\) 變為 \(\text{b}\),\(\text{b}\) 變為 \(\text{a}\) 的結果,然后我們構造 \(s_1="\text{a}",s_i=s_{i-1}+\overline{s_{i-1}}\),再定義 \(\text{hash}(s)\) 為字符串 \(s\) 的哈希值。那么顯然有 \(\text{hash}(s_i)=\text{hash}(s_{i-1})\times base^{2^{i-2}}+\text{hash}(\overline{s_{i-1}}),\text{hash}(\overline{s_i})=\text{hash}(\overline{s_{i-1}})\times base^{2^{i-2}}+\text{hash}(s_{i-1})\),二者相減發現剛好可以表示為 \(\text{hash}(s_i)-\text{hash}(\overline{s_i})\) 的形式。於是我們記一個 \(f_i=\text{hash}(s_i)-\text{hash}(\overline{s_i})\),那么 \(f_i=f_{i-1}\times(base^{2^{i-2}}-1)\),而 \(base^{2^{x}}-1=(base^{2^{x-1}}+1)(base^{2^{x-2}}+1)\cdots(base+1)(base-1)\),由 \(2\nmid base\) 知這 \(x\) 個括號里的東西全是偶數,故 \(2^{x+1}\mid base^{2^x}-1\),於是 \(2^{i(i-1)/2}\mid f_i\),故對於 \(i\ge 12\),\(\text{hash}(s_i)=\text{hash}(\overline{s_i})\),構造一個長度 \(4096\) 的字符串即可叉掉。
這個故事告訴我們,以后千萬不要寫自然溢出哈希了