这道题是我出题花费时间最多,也是我最喜欢的一道题目。我暑假期间编写题目网站、调节每种 Hash 算法的难度、写解题代码、与其他人讨论是否有非预期解法等等,前前后后花了很多天的时间。
所谓我发明的新的工作量证明算法,就是服务器给出一个后缀 suffix
,我需要生成两个随机字符串 nonce1
和 nonce2
,使得 hash(nonce1+suffix)
和 hash(nonce2+suffix)
相同的二进制位数量超过某一个值,这个值对于不同的 Hash 算法是不一样的
直接在 Google 搞出来的 sha1 碰撞 那两个 pdf 后面加上 suffix
提交即可,因为是 Hash 碰撞,所以所有二进制位都是相同的
这次使用已有的 md5 碰撞加上后缀会发现不给你 flag 了。期望解法有两种,一种是按照王小云的论文搞出来一个不完全的碰撞(我没研究),另一种是真的穷举。
我是用 C 语言写的穷举程序。为了偷懒,我在 python 解题脚本中生成了一堆 md5 写入一个二进制文件,然后调用 C 程序来穷举,C 程序就只需要算异或和统计二进制位的个数了。在 C 语言中使用 __builtin_popcountll
函数统计二进制位中 1 的个数,一条 POPCNT 指令就可以统计 64 bit,速度很快,一分钟之内有很大概率可以跑出来。听说有的同学还使用了 GPU 穷举,关于优化这块大家就各显神通了。
穷举是不可能的,即使你用大型超算都不太可能在比赛时间内跑出来。所以呢?期望解法是从比特币的区块链里面找数据。比特币的工作量证明算法是 sha256,现在区块链里面的每一个区块哈希前面都有大约 80 个二进制 0(多么疯狂啊),所以拿它们来找共同 bit 数很多的哈希值,自带了大约 40 位的加成(因为本来 80 位在期望上也有 40 位是相同的)。你需要想办法下载比特币所有区块的哈希,然后两两配对来看一下相同的 bit 数量。如果达到了题目要求,就是下载它们的区块头部,区块头部的两次 sha256 就是最终的 hash,你需要计算一次 sha256,然后结果就是你要提交的数据。不过,我们还是需要满足一个字符的 suffix 要求,这个只要你不断 getjob,总是可以很快拿到你想要的 suffix 的。
解题脚本:https://github.com/zzh1996/mining_pool_of_Z/blob/master/solution/solve.py
注:我设计题目和分析的过程都可以在上面这个仓库中找到