本文上半部分为 David A. Harding 在 Bitcoin Stack Exchange 问答网站上的回复,解释了 “时间扭曲攻击”。时间扭曲攻击是 “共识清理(The Great Consensus Cleanup)” 软分叉提议尝试解决的一种共识层面的弱点。然而,在应用共识清理软分叉的
原文链接:https://bitcoin.stackexchange.com/questions/75831/what-is-time-warp-attack-and-how-does-it-work-in-general/75834#75834 作者:David A. Harding
比特币协议(共识规则)对区块头中的时间戳有两项相关的规则:
就像你在问题中提到的,挖矿难度的变化幅度,是基于一个长达 2016 个区块的难度调整周期的第一个区块和最后一个区块的时间戳(的差值)计算出来的。
给定上述规则,如果所有矿工一致行动,他们可以在一个周期的前 2015 个区块中,按照 MTP 规则,让每一个区块的时间戳仅往前拨 1 秒(相比其上一个区块)(这是 MTP 规则允许的最小增幅)。这样做就仅仅只会带来难度的些许降低,但想想看,在他们将最后一个区块的时间戳拨到稍稍超过当前真实时间时,MTP 规则会怎么样:中值根本不会改变。
真实的时间戳是以秒为单位的,但这里我们用天为单位,表示一组以当前时间为基准的 11 个时间戳:
[-13, -13, -13, -13, -13, -13, -13, -13, -13, -13, 0]
译者注:前面的 “-13” 意味着这些时间戳表示的时间是真实时间的 13 天以前。
那么,这 11 个区块的时间戳中值依然是 -13,意思是,在矿工在难度调整周期的最后一个区块中使用稍稍超过当前时间的时候,再往后,他们就又不需要让时间戳往前拨动超过 1 秒了 —— 下一个难度周期的第一个区块,又可以使用 -13 的时间戳,也即该难度周期又从 13 天以前开始。
在这第二个难度调整周期的末尾,矿工们可以再次将时间戳尽可能往前拨,所以,协议会认为花了 28 天才挖出这个周期的所有区块 —— 只达到预期速度的一半 —— 所以,就将再下一个周期的挖矿难度降低一半。
在这个时刻,用在 MTP 规则中的数值看起来是这样的:
[-27, -27, -27, -27, -27, -27, -27, -27, -27, -27, 0]
矿工可以不断重复这种攻击(将一个周期中前面的区块的时间戳尽可能往后拨,将最后一个区块的时间戳尽可能往前拨),不断降低难度,直到挖出 2016 区块用时不到 2016 秒,也即无法进一步降低难度的时候(因为 MTP 要求每个区块的时间戳至少要推进 1 秒)。
你的主要问题是,这样的攻击,如果没有矿工多数的串通,是如何可能的。现在你已经看到了,在所有矿工都串通的时候,攻击是如何可能的。应该可以看出,对时间戳的选择,让一个足够幸运、能够找到区块的攻击者矿工可以可靠地阻止中值时间跳转到一个诚实的数值。
举个例子,设想过往 11 个区块的时间戳是这样的:
[-27, 0, -27, 0, -27, 0, -27, 0, -27, 0, -27]
如果你排序这些时间戳、找出中值,你会发现中值是 -27,即使 5/11(45%)的哈希算力都是诚实挖矿的。但是,这岂不意味着攻击者矿工还是要拥有 55% 的哈希算力?也许不用,对于一个占有超过 30% 的哈希率的大矿工来说,可以使用 “自私挖矿” 攻击来获得优势,或者该矿工可以直接威胁要让其它拥有诚实时间戳的区块变成过时的、无后续的区块(“孤儿块”)、让诚实矿工只能赚到更少收益。
我个人并不认为这种攻击在比特币上很有可能出现,因为它执行起来很慢,而且很显眼,但别的一些协议的设计者可能在改变参数需要留个心眼,因为这些参数更改可能让攻击更容易执行。
原文链接:<https://delvingbitcoin.org/t/zawy-s-alternating-timestamp-attack/1062>
作者:murch
@zawy 昨天在 Testnet 4 PR 中介绍了一种攻击。我会用我的理解表述一下。
类似于时间扭曲攻击,这种攻击要求攻击者能够选择占多数的区块的时间戳,但与时间扭曲攻击不同的是,它并不依赖于难度调整周期不重合的特点(即,在度量难度周期持续期时候的差一错误(off-by-one error))。这种攻击看起来在理论上是可靠的,虽然需要执行 16 星期的自私挖矿(而且可能要以 50% 的哈希算力为前提),理应使其变得不现实。
这种攻击的大体思路是扣住绝大多数区块的时间戳,但在难度调整周期的最后一个区块交替放置表示未来和表示过去的时间戳,从而在最大限度降低和提高难度之间来回跳跃。这种过热与低温,让攻击者可以在相同时间内制造出比诚实矿工的的预期产出数量多得多的区块。
具体来说,攻击者是这样做的:
攻击者先让时间戳尽可能往后拨。在最初的描述中,时间戳每个区块只推进 1 秒,但时间戳只需每 6 秒推进一次。矿工占据稍微占多数的哈希算力,所以我们预期,区块会每 20 分钟出现一个。我们假设出块的速度在一个难度周期中是恒定的,以简化讨论:
标签 | 高度 | MTP [s] | 时间戳 [s] | 实际经过的时间 | 难度 |
---|---|---|---|---|---|
起点 | 0 | < 0 | 0 | 0 | D |
1 | < 0 | 0 | 20 min | D | |
2 | < 0 | 0 | 40 min | D | |
3 | < 0 | 0 | 60 min | D | |
… | … | … | … | … | |
6 | 0 | 1 | 2 h | D | |
… | … | … | … | … | |
12 | 1 | 2 | 4 h | D | |
… | … | … | … | … |
攻击者将难度调整周期的最后一个区块的时间戳设为攻击起始日期的 8 周以后。这个区块不会被其它节点接受,因为它超过了节点的本地时间两个小时以上,那么攻击者在这里(暂时)将自己从网络中分叉出去。然而,这个表示未来的时间戳,让攻击者可以将下一个周期的难度变成本周期难度的 1/4 。第二个难度调整周期的第一个区块的时间戳也需要设为(攻击起始日期的) 8 周以后,以应对共识清理提议的要求。
标签 | 高度 | MTP [s] | 时间戳 [s] | 实际经过的时间 | 难度 |
---|---|---|---|---|---|
起点 | 0 | < 0 | 0 | 0 | D |
… | … | … | … | … | |
2014 | 335 | 336 | 4 周 – 40 分钟 | D | |
2015 | 335 | 8 w | 4 周 − 20 分钟 | D | |
2016 | 336 | 8 w | 4 周 | D/4 |
攻击者继续在第二个难度周期中挖矿,以尽可能少的幅度推进时间戳,并再次将最后一个区块的时间戳推进到又 8 周以后,从而再次将难度降低 4 倍。因为占据了大约一半的哈希算力,攻击者挖完第一个难度周期需要 4 周,但第二个难度周期就只要 1 周了。
标签 | 高度 | MTP [s] | 时间戳 [s] | 实际经过的时间 | 难度 |
---|---|---|---|---|---|
起点 | 0 | < 0 | 0 | 0 | D |
1 | < 0 | 0 | 1200 | D | |
… | … | … | … | … | |
2014 | 335 | 336 | 4 周 – 40 分钟 | D | |
2015 | 335 | 8 w | 4 周 − 20 分钟 | D | |
2016 | 336 | 8 w | 4 周 | D/4 | |
2017 | 336 | 337 | 4 周+ 5 分钟 | D/4 | |
2018 | 336 | 337 | 4 周 + 10 分钟 | D/4 | |
… | … | … | … | … | |
4030 | 671 | 672 | 5 周 − 10 分钟 | D/4 | |
4031 | 671 | 16 w | 5 周 − 5 分钟 | D/4 | |
4032 | 672 | 16 w | 5 周 | D/16 | |
4033 | 672 | 673 | 5 周 + 75 秒 | D/16 |
Zawy 也称攻击者可以为难度调整的最后一个区块切换设置尽可能小的时间戳和尽可能大的时间戳。这会导致某些难度调整周期的名义经过时间为复数。不过,难度调整算法会将其等同于经过了半个星期,并依然将难度提高仅仅 4 倍。即使遵守共识清理提议的新限制(不允许将下一个难度周期的第一个区块的时间戳设得比上一周期的最后一个区块还要早),攻击者依然可以在起始难度的 1/4 和 1/16 之间切换。攻击者每 5/4 周就可以挖完两个难度周期的区块。
标签 | 高度 | MTP [s] | 时间戳 [s] | 实际经过的时间 | 难度 |
---|---|---|---|---|---|
起点 | 0 | < 0 | 0 | 0 | D |
1 | < 0 | 0 | 1200 | D | |
… | … | … | … | … | |
2014 | 335 | 336 | 4 周 – 40 分钟 | D | |
2015 | 335 | 8 w | 4 周 − 20 分钟 | D | |
2016 | 336 | 8 w | 4 周 | D/4 | |
2017 | 336 | 337 | 4 周+ 5 分钟 | D/4 | |
2018 | 336 | 337 | 4 周 + 10 分钟 | D/4 | |
… | … | … | … | … | |
4030 | 671 | 672 | 5 周 − 10 分钟 | D/4 | |
4031 | 671 | 16 w | 5 周 − 5 分钟 | D/4 | |
4032 | 672 | 16 w | 5 周 | D/16 | |
4033 | 672 | 673 | 5 周 + 75 秒 | D/16 | |
… | … | … | … | … | |
6047 | 1007 | 1008 | 5 w 42 h − 75 s | D/16 | |
6048 | 1008 | 1009 | 5 w 42 h | D/4 | |
6049 | 1008 | 1009 | 5 w 42 h + 5 min | D/4 | |
… | … | … | … | … | |
8063 | 1343 | 1344 | 6 w 42 h − 5 min | D/4 | |
8064 | 1344 | 16 w | 6 w 42 h | D/16 | |
8065 | 1344 | 16 w | 6 w 42 h + 75 s | D/16 | |
… | … | … | … | … | |
10079 | 1679 | 1680 | 6 w 84 h − 75 s | D/16 | |
10080 | 1680 | 1681 | 6 w 84 h | D/4 | |
10081 | 1680 | 1681 | 6 w 84 h + 5 min | D/4 | |
… | … | … | … | … | |
12095 | 2015 | 2016 | 7 w 84 h − 5 min | D/4 | |
12096 | 2016 | 16 w | 7 w 84 h | D/16 | |
12097 | 2016 | 16 w | 7 w 84 h + 75 s | D/16 | |
… | … | … | … | … |
一旦实际经过的时间达到 16 周,攻击者就可以公开自己暗中挖出的链,并且(按照假定)其累计工作量会略微更高,从而将公开网络上 16 周的交易活动作废、重组大约 8064 个区块、获得大约 39816 个区块的奖励,而且可能收到比公开网络上更多的交易手续费,因为可以打包在公开网络缓慢出块期间得到广播的一切不冲突的交易。
在昨天读完这种攻击的描述后,我有了一种微调它的想法:
不将周期的最后一个区块的时间戳交替设为最小值和 16 周之后,攻击者可以转而在一个周期中降低到最小值,然后分两步走向表示未来的时间戳:
label | height | MTP [s] | timestamp [s] | elapsed time [s] | difficulty |
---|---|---|---|---|---|
start | 0 | < 0 | 0 | 0 | D |
1 | < 0 | 0 | 1200 | D | |
2 | < 0 | 0 | 2400 | D | |
3 | < 0 | 0 | 3600 | D | |
… | … | … | … | … | |
6 | 0 | 1 | 7200 | D | |
… | … | … | … | … | |
12 | 1 | 2 | 14400 | D | |
… | … | … | … | … | |
2014 | 335 | 336 | 4 w − 40 min | D | |
2015 | 335 | 8 w | 4 w − 20 min | D | |
2nd diff period | 2016 | 336 | 8 w | 4 w | D/4 |
2017 | 336 | 337 | 4 w + 5 min | D/4 | |
2018 | 336 | 337 | 4 w + 10 min | D/4 | |
… | … | … | … | … | |
4030 | 671 | 672 | 5 w − 10 min | D/4 | |
4031 | 671 | 16 w | 5 − 5 min | D/4 | |
3rd diff period | 4032 | 672 | 16 w | 5 w | D/16 |
4033 | 672 | 673 | 5 w + 75 s | D/16 | |
… | … | … | … | … | |
6047 | 1007 | 1008 | 5 w 42 h − 75 s | D/16 | |
6048 | 1008 | 1009 | 5 w 42 h | D/4 | |
6049 | 1008 | 1009 | 5 w 42 h + 5 min | D/4 | |
… | … | … | … | … | |
8063 | 1343 | 1344 | 6 w 42 h − 5 min | D/4 | |
8064 | 1344 | 8 w | 6 w 42 h | D/16 | |
8065 | 1344 | 8 w | 6 w 42 h + 75 s | D/16 | |
… | … | … | … | … | |
10079 | 1679 | 1680 | 6 w 84 h − 75 s | D/16 | |
10080 | 1680 | 16 w | 6 w 84 h | D/64 | |
10081 | 1680 | 16 w | 6 w 84 h + 19 s | D/64 | |
… | … | … | … | … | |
12095 | 2015 | 2016 | … | D/64 | |
12096 | 2016 | 2017 | … | D/16 | |
12097 | 2016 | 2017 | … | D/16 | |
… | … | … | … | … | |
14111 | 2351 | 2352 | … | D/16 | |
14112 | 2352 | 8 w | … | D/64 | |
14113 | 2352 | 8 w | … | D/64 | |
… | … | … | … | … | |
16127 | 2687 | 2688 | … | D/64 | |
16128 | 2688 | 16 w | … | D/256 | |
16129 | 2688 | 16 w | … | D/256 | |
… | … | … | … | … | |
18143 | 3023 | 3024 | … | D/256 | |
18144 | 3024 | 3025 | … | D/64 | |
18145 | 3024 | 3025 | … | D/64 | |
… | … | … | … | … |
这不仅允许攻击者创建更多区块,而且可以指数级降低难度。
<!--StartFragment-->
让软分叉对时间戳提出额外的要求,要求一个难度周期 N 的最后一个区块的时间戳大于同一周期的第一个区块,可能是有用的。即,要求:
我不认为诚实挖矿在跨难度周期时推进时间戳(至少一秒,这是由现有的 MTP 规则间接引起的)的需要会跟这条规则冲突,除非像上面说得那样对时间戳进行极端的操控。但是,就我所知,这样的规则应该能减少这种攻击界面。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!