隔离见证的详解

隔离见证的详解

vatten Yellow v2 · 2016-02-24 15:11 · 203 次点击 · 4.25783758

今天又读了些技术资料,把我的发现分享一下 (纯干货!)

隔离见证是对交易结构的一种优化,(其实没有这种优化也无所谓,比特币也照样工作,但程序员么总是喜欢完美主义,而且改进后可以带来一些附加的功能,所以连Gavin都说是个很酷的想法)。隔离见证软分叉则是一种非常复杂的方案,甚至连香港公开会上都提到即使软分叉实现后也要用硬分叉来重新修正,这里不提

还是用之前那个账簿的比喻

账簿的每张纸上可以容纳1000行,然后这张纸可以用来填写一笔又一笔的交易

有两笔交易甲和乙,其中甲交易是将1个比特币从地址A发送到地址B,而乙交易是将1个比特币从地址B发到地址C,都是一对一交易,以乙交易为例,在账簿里大致是这样填写的:

交易从左到右分为六栏:

  1. 版本号
  2. 输入的编号
  3. 输入
    前一交易的哈希值
    前一输出的编号
    签名脚本长度
    签名脚本(签名和地址B的公钥)
    顺序码
  4. 输出的编号
  5. 输出
    金额
    兑现脚本长度
    兑现脚本 (地址C及其兑现条件)
  6. 区块锁定时间

细节不谈,输入是用来签名并转账前一个输出里的地址中的币的,而输出则是用来注明转账金额和转账的目标地址以及未来的兑现条件的

签名脚本(scriptSig)和兑现脚本(scriptPubKey)是最重要的。兑现脚本就是一道考题,验证地址C的一个特殊的签名是否通过,而签名脚本则是回答前一道题,也即地址B的兑现脚本(包含在前一个交易甲里,同样的格式),签名时需要有地址B的私钥才能提供正确的签名。地址B是前一笔交易甲的兑现脚本里给出的,而地址C则是交易乙的目的地,这样交易就实现了从地址B转账到地址C。而未来要花地址C的币,就得有地址C的私钥并满足地址C的兑现条件

一旦在交易中写错了兑现脚本,使那道题无解,那地址C的币就永远花不了了。而如果写成一道简单的题,那很多人都能答上来就看谁先花了

隔离见证和这个的关系?问题就在签名脚本里,签名脚本由签名+地址B的公钥组成

获得签名的步骤:先构建这整个交易乙,然后对整个交易乙进行哈希运算,最后对运算结果用私钥以DER算法签名

不过,既然签名是包含在交易乙中,还没有签名的时候怎么可能构建整个交易乙?于是先初步构建交易乙的草案,签名脚本处用交易甲里地址B的兑现脚本先填充,等签名产生后再用签名+地址B的公钥替换到签名脚本里去

在交易乙中,签名就处在第三栏那个位置,也就是交易的中间,这个在比太公开课上讲过

这就联系到交易延展性问题。TXID是交易的辨识码,是由交易乙的全部数据算哈希产生的。但这个值不是唯一的,有两大原因:第一个就是上述的签名不是唯一的。也就是说,上面在用私钥对初步构建的交易乙的哈希值进行签名时,可能签名结果是不一样的,但验证起来都符合,这是OPENSSL对签名编码要求不严格的问题。Pieter试图收紧DER签名规则,也就是众所周知的导致2015年7月4日硬分叉的BIP66。但收紧DER签名规则不能完全解决问题,因为ECDSA签名可以用一个负值产生同样有效却不一样的签名,这是无论怎么收紧DER签名规则都不可改变的

此外还有个问题显而易见:以上过程中,在算出签名后再把签名+地址B的公钥替换到签名脚本里去,就意味着事后可以改动签名脚本,却不会影响签名的有效性(因为签名已完成),而签名脚本一旦改了,整个交易的哈希值也即TXID就变了,但交易仍然有效,这也是目前没法解决的问题

总之,以目前的这个格式,签名塞在想要签名的东西里面带来了很多不便(这大概也是为何Pieter说:“如果你从头设计,你肯定不会把比特币设计成这个样子。”)如果能把签名移到交易最后面作为一个延伸段,就不需要预先用什么东西填充才能算签名了,而签名后交易就锁定了,只要改动一个字就会导致签名无法验证通过。而算TXID的时候也不需要包含签名那部分一起算哈希,那TXID就是唯一的,交易延展性问题就彻底解决了。总之,签名移出来,交易结构清晰了,交易延展性问题也解决了,这大概就是隔离见证的基本好处

不过,要做这样大规模的对交易结构的改动,意味着现有的7年以来的所有比特币标准库和接口、技术资料等等全都需要改过,而且所有功能都无法兼容于旧版软件,只能用硬分叉来实现。同时,对绝大多数等待交易2/3个确认再花的人来说,交易延展性问题根本就不存在(TXID不唯一的问题只影响未确认交易),所以也不是一个很紧迫的需要改进的方面,属于系统的优化,按优先级来说也不是很高

cndx medium avatar
1

cndx Yellow v    8 天前

楼主好文,点赞。

简单点说
原格式是签名验证放中间,替换后,再整体计算交易ID,当签名变时,ID就会变。
这种交易可拓展改变的攻击是被坏人用,破坏性还是蛮大的。
门头沟倒闭,就是说被这种漏洞盗走的币,当然可信度不高。

而隔离验证方案。
简单点说就是把这个签名验证从中间,移动到后面,这样交易ID就可以不包含签名,从而将交易ID固定下来。从根本上解决交易可锻性问题。
更加重要的是这种结构,会更加合理,利于币应用的开发。

隔离验证可以软分叉也可以硬分叉。

楼主描述的所有标准库,接口等等重来是硬分叉。

而目前进行的是软分叉,即有一定兼容性,你完全不用更新也可以正常使用。普通交易可以和隔离验证交易长期共存。

就像私钥后来发现有压缩格式的私钥,但原来未压缩的私钥依旧可以使用。两者共存。

比特币感谢地址: 1DogeKd9JrUNzFaLEyWAVxCVXSvWxe6sAm
vatten medium avatar
2

vatten Yellow v    8 天前

我觉得这个写的还是不够简单,恐怕能明白的人不多。签名可以用私钥盖章来描述,但哈希想不到什么合适的比喻

vatten medium avatar
3

vatten Yellow v    7 天前

再详解一下隔离见证软分叉

以上说过,隔离见证需要彻底修改每个交易的格式,把签名从中间移到交易外面去,但这样的改动必然会导致新格式的交易不符合旧节点的要求而被拒绝。用账簿的例子来说,就是那些负责记账的会计(全节点)一旦收到这些格式不合要求的交易,都会认为其无效而直接剔除,都没有资格进入内存池(交易发送到网络后,经初步验证的都先在内存池中排队,然后最先算出难题获得记账权的矿工从内存池中取出尽量多的交易写到账簿的一页(区块)里)。这样新格式的交易就无法发送到网络,更不要说被写到账簿的某一页里

所以每个会计的规则和账簿格式都需要升级,一定是不兼容旧版的硬分叉

但Luke_jr是个黑客,擅长于寻找防守严密的系统的安全漏洞而攻破(比如前一阵试图去Classic的代码库里埋一个修改PoW的地雷),于是他就找到了这么个漏洞,可以让这样新格式的交易在网络中被旧节点接受而不被拒绝

比特币为保证资金安全,有层层防护。所以新格式的交易要想骗过旧的节点必须要经过两大安全检查:第一是对交易的检查,第二是对区块的检查。

先看下要通过交易的安检,需要做多少工作

和之前账簿加夹层的原理一样,要通过对交易的检查,办法就是新格式的交易分成两部分,其中一半完全和原来的交易格式一样,只是去掉了签名,旧节点可见,而另一半包含有签名和其他新规则,旧节点不可见

上面说过,每个交易的兑现脚本都要求下一个交易花这个地址的币时需要通过脚本中的签名验证,那什么样的交易没有签名却仍然可以花币呢?显然,这只需在兑现脚本里取消需要签名的规则

用上面的例子,交易乙的兑现脚本里原来要求的验证条件是:下一个交易丙的哈希值用地址C的私钥签名,该签名可用地址C的公钥来验证通过(验证过程就是上面图中的OP_CHECKSIG,也是整个比特币交易中最复杂的一部分)。但在新规则下,新交易乙的兑现脚本里则写明地址C的币任何人都可以花,无需签名

这样,新交易乙发到比特币网络,对旧节点来说仍然是有效的:你愿意任何人都花你的币是你自己的问题,系统认为有效。但新交易乙发到网络以后,就导致交易丙里不需包含签名,而新交易丙的兑现脚本里也是任何人都可以花的规则,于是新交易丁里也不需要包含签名,以此类推。当新版本实现后,在旧节点眼里所有新交易所转账的目的地址的币都体现为任何人都可以花

同时,在新规则下,新交易乙只是新交易的一半,另外一半同时发送到网络,可称为乙的延展交易,但这部分数据只会被新节点而不会被旧节点接收,因为旧节点完全不认识这段数据。这个延展交易里则包含了原本应该在兑现脚本里的验证规则和签名,公钥等等。当新节点要花地址C的币的时候,要按照延展段里的规则验证签名和公钥,规则与原来的兑现脚本一样

当旧节点发送原来格式的交易时,新节点可以做到理解和验证,只需在新规则中允许新旧两类不同交易的同时存在即可。这样看来,旧节点既可以收新格式的交易,又可以发旧格式的交易,就实现了不需升级即可正常工作的目的

聪明点的人马上就会想到:既然地址C的币在新规则下对旧节点来说显现为任何人都可以花,那肯定会有黑客立刻广播交易到比特币网络中来试图花这些任何人都可以花的币,而这些交易也都是有效的,会立刻被旧节点接受,但应该不会被新节点接受,新节点会禁止接受这类的交易

实际上这是个两难问题,可能会是个很大的安全漏洞:新节点如果不接受旧节点发布的交易,旧节点就因无法发送交易而全都被迫升级,就不是软分叉了。但如果要接受,就可能会接受这类花任何人都可以花的币的交易而导致用户丢币(可能有各种方式来花这些币,防不胜防)。因此可能新节点不会接受旧节点发布的交易,旧节点还是全都必须要升级来保证安全性,那就和硬分叉没区别了

即使新节点完全拒绝旧节点发布的交易,这些盗币的交易还是可能会进入网络:假设在新规则激活后旧节点只是少数算力,那这些盗币的交易就无法进入新的区块。但去年7月分叉已经证明,即使达到95%共识的软分叉也可能因为SPV挖矿的存在(SPV挖矿有其存在的理由)而导致旧节点会偶尔占多数算力,那时这类任何人都可以花的币就会被旧节点收入区块并延长,而黑客则可能将每个区块中所有的币都倒空了,这就不仅仅象去年7月一样影响到矿工的收益,而是会导致持币者的损失

这就是隔离见证软分叉下新交易如何突破旧节点的安检。可以看到,隔离见证把签名取出来改个交易格式,本来就已经是很复杂冲击很大的变化了,如果不做软分叉,就不需要构造这些“任何人都可以花”的交易,就不会出现那么多安全漏洞。用非正常的手段一定会引起非正常的漏洞,而且很可能使得整个情况扑簌迷离,难以查错

此外,花那么大劲,只是为了解决交易延展性问题,也即未确认交易的编号唯一性。而比特币的基本使用原则就是未确认交易是不安全的,因为块可能会被孤立掉。费那么大力气就是为了实现一个可有可无的功能?这无论从哪个角度逻辑上都说不通。。。当发现完全不合逻辑的事情时,往往后面有更大的局,这就导致我怀疑隔离见证后面有其他的目的,直觉感觉是政治上的,而Blockstream猛推隔离见证则使我这个怀疑进一步加深

BitThink medium avatar
4

BitThink Yellow v    7 天前   via iPhone

1)再次强调新节点接受数据见证和交易是在一起的。
2)软分叉在95%启动,不可能在少数算力时激活,所以如果有旧节点要花费那些它认为是任意人可花的币 不可能进新区块 一旦被5%的旧挖矿节点收录则必然马上被孤立抛弃。
3)各交易所和大商户不可能在95%启动时还未更新版本,而一旦启动后新节点无论如何不会承认旧区块,即便旧分叉临时成为最长链也是如此。所以即便再发生SPV挖矿事故,出事矿池也只能是退回承认损失。
4) 旧节点只是不能花费这种本就不是它的币 正常交易不受影响 无需立即升级。你怎么能说因为无法偷钱而必须被迫升级呢?即便可能暂时被误导到一个错误的分叉也不必被迫升级,只有被永远隔绝于一个旧分叉才会被迫升级。即便正常状态的正常节点有时也有被孤块误导的可能。你本来软硬分叉已经理解得很透彻,这里为了立场,不知是有意无意又混淆。

不要由于自己的立场而被偏见蒙蔽。要反对SW就去找出真正漏洞,不要老是在找这些“一眼就能看出”的问题,你这样等于在说社区的所有人都太傻了 到现在连这么明显的漏洞都没看出来。

比特币感谢地址: 1Aug9NQPT1Hotn6BGhc14YeRHszMduhU79
vatten medium avatar
5

vatten Yellow v    7 天前

@BitThink

你搞混了吧,我这里通篇说的都是交易,区块还没谈到呢,比交易又要复杂一些。有关区块那部分Pieter在香港会上有大致解释,但有关交易部分他只是一笔带过

但不搞明白交易是不行的,每一笔交易是最基础的元件,也是最难搞明白的地方,比如说上面那幅图OP_CHECKSIG,花了我几个小时。因为区块是由一笔笔交易组成的,而交易在还没有区块之前是要先进入节点的内存池里的,所以节点是否接受交易和节点是否接受区块是两码事

BitThink medium avatar
6

BitThink Yellow v    7 天前   via iPhone

@vatten 交易格式见bip104。代码实现遵照bip。

比特币感谢地址: 1Aug9NQPT1Hotn6BGhc14YeRHszMduhU79
vatten medium avatar
7

vatten Yellow v    7 天前

@BitThink

不要由于自己的立场而被偏见蒙蔽。要反对SW就去找出真正漏洞,不要老是在找这些“一眼就能看出”的问题,你这样等于在说社区的所有人都太傻了 到现在连这么明显的漏洞都没看出来。

不赞成这种说法,立场不是因为盲目信任权威或一堆权威,权威那么多,你信哪个?何况现在即使权威都说隔离见证在某些情况下会导致网络分成两条互不兼容的链:
http://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-January/012301.html

根据我的判断,除了Pieter自己,core程序员里也没有人敢说自己真正懂这个东西,因为这个主意是Pieter搞出来的,别人没法学会Pieter的思考方式

比特币的宗旨是不信任任何人,只信任计算机代码和算力。所以不管一个方案是谁提出的,最终要让我相信,我必须自己看明白是干啥的。当然了,我不需要关注每一行代码,因为代码都是为了实现某个功能而写的,只需要把功能图看懂就行了,代码只是查错的时候才需要关注

打个比方,一个交易你用getrawtransaction来看,就是一串数字,那这串数字对不懂的人来说就和乱码一样,但发送到比特币网络的节点,节点验证通过后就会放到内存池里,矿工则可以打包到区块里。那么归根到底,我只要知道这一串数字的每个部分都是做什么的,实现什么功能的,那这个交易的全部细节就都清楚了。而这串数字是按什么规范写的,也就是我说的那六栏,比特币WIKI上都有资料,任何人都可以看懂,最多需要一两天,我花了4个小时

你看懂以后,就不需要盲目信任权威了,或者说起码你对局面的了解就达到和core程序员一样的程度了,如果人人都看懂了,谁还会把core程序员奉上神坛呢?他们无非就是些实现功能的码农而已。如果你把core捧的和权威一样,就足以证明你没搞懂比特币是怎么工作的

但如果你功能不懂,始终搞不清楚是怎么回事,那决策上就会有极高的难度,很可能本该往东走的你就往西走了,结果因为无法做决策,或屡做错误决策,最终就只能乖乖的跟着程序员的指挥棒走。而一旦被程序员发现你这个弱点,他们就会开始有意误导你而试图实现自己想实现的目标,或者说起码你不能排除这个可能

交易格式见bip104。代码实现遵照bip
BIP104和隔离见证没关系,而且根据我上面的不信任任何人的思路,这个BIP对证明你是支持还是反对隔离见证毫无帮助,必须有给出详细的分析过程来说明隔离见证为什么好,好在哪里,否则说有利于这个有利于那个,谁信啊?

BitThink medium avatar
8

BitThink Yellow v    7 天前   via iPhone

@vatten 论述SW优点及缺点的技术文章很多了,有时人有了先入为主就容易选择性的阅读。我支持合理质疑,反对迷信权威。只是你每次反对都是找一些太明显的“漏洞”,明显到不可能存在。尽管如此,我还是尽我可能给你解释了为什么你说的那些漏洞不存在。听不听只能由你了。我还是希望大家客观,技术上的讨论尤其要客观,因为那个对就是对 错就是错 不像观点之争 无所谓对错。

比特币感谢地址: 1Aug9NQPT1Hotn6BGhc14YeRHszMduhU79
vatten medium avatar
9

vatten Yellow v    7 天前

@BitThink

你有没有想过,为什么这些漏洞如此明显却还有人还在支持SW呢?夸隔离见证的文章,到目前为止我看了一下,绝大多数你追其根源都是来自于Blockstream控制的几个媒体,你去看那个所谓的支持公司的列表,几乎都是一两个人的小公司开发钱包软件的,这类人因为最不受软件升级影响,是最容易说服的,这样的舆论控制手段对不明真相的群众有很大的蛊惑力,但你要问权威的意见,Gavin说了,不是个短期内能实现的方案,而且该用硬分叉实现;而Jeff说了对大型已开发了大多数相关应用的企业来说要很久才能实现,而Peter Todd也说有些安全漏洞,所以目前为止都是些小公司在表示支持

技术上的讨论当然要客观,但因为计算机的东西就是涉及层层翻译,从最底层的一串串010010011到最终功能的实现,7到8次的翻译是不可避免的,所以客观也不是那么显而易见,所以必须层层验证。只要有一层你翻错了,结论就是相反的。有这个能力的人是很少的,如果你自己能写一串0和1实现隔离见证的功能,才能证明你是懂的,但除了Pieter估计谁也没这个能力

我的看法就是隔离见证因为其彻底修改比特币基础架构,任何普通用户完全无法理解它是干什么的,所以是不会被接受的,涉及到投资者大笔资金,谁敢去用一个完全重写的,根本就没有得到市场和7年时间测试的金融系统

BitThink medium avatar
10

BitThink Yellow v    6 天前   via iPhone

拭目以待吧 我觉得隔离验证最短半年 最多一年就会被全面使用 classic的路线图在第三阶段也已经加入了SW。

Advertisements
隔离见证的详解

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s