Challenge
自定义 PoW(Proof of Work)类
给定当前 session 的 block data,找一个 32 字符大写 HEX nonce,使
Skein512 hash 以 00000000 开头。
Britcoin
1 2 3 $nonce_zero = GWF_Skein ::hashString ($payload ); $hash = GWF_Skein ::hashString ($nonce_zero . $nonce );
要求: - nonce 匹配 ^[A-F0-9]{32}$(32 字符大写 HEX) -
hash 使用 Skein512 算法(Threefish + UBI 模式) - hash
的大写 hex 结果以 00000000 开头(8 个零 = 32 bits 难度) -
输入是 ASCII 字符串
nonce_zero + nonce,不是 raw bytes —— 最常见的坑
Solution
1. 获取参数
挑战页面直接显示 computed nonce_zero(Skein512 对 block data 的
hash):
1 2 This is the computed nonce zero for comparison: F70F9DE66EA5... Your nonce is your answer, uppercase 32 hex digits.
拷贝 nonce_zero 值即可。该值在 session 有效期内固定。
2. 库选择
必须使用
pyskein 。pycryptodome 的 Skein 实现与
PHP 的 GWF_Skein 输出不兼容(Skein
规范版本差异),会产生完全不同的 hash
用官方规格 britcoinspecs.grfc
的参考向量验证库兼容性和拼接逻辑(以下两个断言已实测通过):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from skein import skein512NZ_REF = ( '05113B96005C00ABE1BC67C7108EBDAA5B030A03F3FB2DB3279A1730D96E41C4' 'B1D43DF46BAF31B367A960005B9A7BFF48168722E336A0A900181861F55A88F4' ) assert skein512(b'livinskull' ).hexdigest().upper() == NZ_REFassert skein512(NZ_REF.encode() + b'A' * 32 ).hexdigest().upper() == ( '6473BE426B22ED34DFF9AA5C1547CB3BCEC350B06910F639338AF1FA6F5A6DDA9' 'B938BBBB9B6F956439A90ED7A3996711DC30C00D1C8FA2E8D207EB2D1D03476' )
两个向量都通过 = 库兼容 + ASCII 拼接逻辑正确。注意向量 2 的
nonce_zero 按大写 ASCII
参与拼接,用小写会产生不同结果。
3. PoW Miner
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import timefrom skein import skein512from itertools import countnonce_zero = 'F70F9DE66EA5...' st = time.time() prefix = nonce_zero.encode() print ('Mining prefix 00000000...' )for i in count(): nonce = f'{i:032x} ' .encode() h = skein512(prefix + nonce) if h.hexdigest().startswith('00000000' ): elapsed = time.time() - st nonce_str = nonce.decode().upper() print (f'Found: {nonce_str} ' ) print (f'Hash: {h.hexdigest().upper()} ' ) print (f'Time: {elapsed:.0 f} s' ) break
关键细节: - nonce 用 f'{i:032x}'.encode() → hash
对小写 ASCII bytes 计算 - nonce_zero
按页面显示的大写原样 .encode() - 拼接:
nonce_zero.encode() + f'{i:032x}'.encode() - 找到后
.decode().upper() 转大写提交
4. 优化多进程
难度 32 bits → 单次命中概率 2^-32,期望 2^32 ≈ 4.3B 次(中位数
≈2.98B)。单核实测 ~885K h/s(期望 ~80 分钟),多进程显著加速:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 from multiprocessing import Pool, cpu_countfrom skein import skein512nonce_zero = 'F70F9DE66EA5...' def check (args ): nz, start, end = args for i in range (start, end): n = f'{i:032x} ' .encode() h = skein512(nz.encode() + n) if h.hexdigest().startswith('00000000' ): return n.decode().upper() return None if __name__ == '__main__' : workers = cpu_count() step = 2 **32 // workers ranges = [(nonce_zero, i * step, (i + 1 ) * step) for i in range (workers)] pool = Pool(workers) try : for result in pool.imap_unordered(check, ranges): if result: print (f'Found: {result} ' ) break finally : pool.terminate() pool.join()
实测(6 workers,~5.7M h/s): - 10 分钟 ~3.4B nonces → 命中率 ≈55% -
30 分钟 ~10B nonces → 命中率 ≈90% - 完整 2^32 扫描 → 命中率 63.2%