编者按:本文来自安比实验室,作者:安比实验室,星球日报经授权发布。回到这一节的问题:为什么说比特币从未实现真正意义上的转账功能。答案很简单,因为比特币系统中根本就不存在账户的概念,账户之间的转账也无从谈起。一个人能在未来打开多少个保险箱,也是未知数。通过上面的解释,我们可知:当pywallet开源库误将1-地址识别为3-地址时,就好像将原本的1-类保险箱改造成了3-类保险箱,而账户持有者还是拿着1-类保险箱的钥匙去解锁,那么自然无法打开保险箱。那么之前zer0to0ne发现的被误锁住的OmniLayer数字资产是否能恢复?是否存在一种可能性,采用1-地址的钥匙去开启3-保险箱?zer0to0ne接着向我们详细解释了两个重要概念P2PKH与P2SH的来龙去脉。这两个名词分别代表了两种不同的比特币交易类型。下面是zer0to0ne的精彩技术细节分析P2PKH——中本聪的伟大发明
PaytoPublicKeyHash顾名思义,是将比特币放入一个保险箱,钥匙孔为公钥Hash。我们最常见到的1-地址本质上就是PublicKeyHash的一种编码。1-地址的生成过程也很简单,将公钥经过Hash160运算得到PublicKeyHash,在PublicKeyHash头部补上前缀0x00,Hash尾部补上校验和,经过Base58便得到了1开头的比特币地址。Base58(0x00+<PublicKeyHash>+Checksum)我们来看看P2PKH交易类型的保险箱构造过程,Alice发送比特币给Bob为例:付款方Alice在构造保险箱的时候需要设置一个锁定脚本:OP_DUPOP_HASH160(Bob收款地址蕴含的PublicKeyHash)OP_EQUALVERIFYOP_CHECKSIG注:我们可以把这一步理解为Alice为Bob定制了一个保险箱,把比特币放入保险箱并用Bob的公钥PubKeyHash上锁。现在这把锁除了持有私钥的Bob,谁都无法打开。当Bob需要花费Alice给他的比特币时,需要提供必要的参数:交易签名+公钥来开启保险箱,使得锁定脚本执行后返回True,这一步通常由钱包自动完成。我们来看看比特币节点是如何校验scriptSig合法性的。
脚本执行过程如图所示,Bob将交易签名后得到的数据,真正的scriptSig应该为<siglen><sig><pubKeylen><pubKey>,比特币脚本执行器从PUSH数据开始,PUSH操作会读取第一个字节获取将要入栈的数据长度信息,然后持续执行比特币脚本,直到最后执行完毕检查执行结果。首先入栈的是<sig>,然后将<PubK>入栈,一次DUP操作将在栈顶复制一份<PubK>,HASH160弹出栈顶的并计算Hash,将结果压回栈中,之后使用EQUALVERIFY弹出Hash对比是否合相等,如果相等则返回True,不相等便标记交易为无效。执行到这一步,暴露了公钥,确保了签名者的身份的正确性,但是黑客或矿工可以通过暴露的公钥构造出一个新的交易替换原始交易,无法保证安全,那么便需要下一步来保证交易无法伪造。此时栈上还有<PubK>和<sig>,执行CHECKSIG,将校验数字签名的正确性,确保了签名者拥有地址对应的私钥。数字签名除了持有私钥的人,谁也无法伪造,执行至此,一笔比特币P2PKH交易已经安全地完成了。再解释一遍:当Bob要花费Alice给他的比特币时,Bob只有用正确的钥匙才能打开Alice留给他的保险箱,把钱放入Bob新构造的一个保险箱里。这时候一些聪明的读者会注意到一个细节:如果Bob取出钥匙,在还未打开保险箱的时刻,区块链上的任何矿工都能看得见这把钥匙的形状,理论上他们是可以立即复制一把钥匙,把Alice留给Bob的保险箱打开并花掉。真的可以这样做吗?显然中本聪考虑了这个问题,这把钥匙中的交易签名是Bob发起的交易的完整签名。假设Bob要将Alice构造的保险箱中的比特币装入一个新的保险箱,这时候Bob出示的钥匙包含了Charlie的公钥Hash,矿工虽然可以复制Bob的钥匙,但是这把钥匙已经隐藏了下一个新保险箱的关键信息,因此矿工无法使用这个复制钥匙来完成别的动作。P2SH——后中本聪时代的重大创新
中本聪设计了一个这么强大的脚本系统,只用来构造转账交易似乎太浪费了,我们试试用其他指令构造一些特别的锁定脚本,并使用其他方式来解锁。例如我们可以构造一个用Hash原象来解锁交易的脚本:OP_HASH160<Hash>OP_EQUAL这个脚本的含义是:当满足Hash160(Pre-image)==<Hash>这个条件时,便可成功将脚本解锁。我们继续通过保险箱的例子来解释,并给这类保险箱起名为3-类保险箱。现在Alice给Bob的比特币锁定在一个由上述Hash160保护的保险箱里,我们姑且称之为哈希锁吧。这把锁依然需要正确的形状才能开启,但是安全性却弱很多,缺少数字签名机制导致钥匙隐藏的关键信息不会随着Bob新建的保险箱而变化。任何矿工都能在Bob亮出钥匙的一瞬间复制出一摸一样的钥匙,抢着去开Alice留给Bob的保险箱,将币转给另一个人Eve,于是原本属于Bob的比特币会被洗劫一空。虽然这个脚本非常不安全,但是它却有两个非常神奇的功能:1.交易构造的输出足够短,意味着比特币节点维护的UTXO缓存占用空间将会大大减小2.Pre-image总是在交易被花费时作为input来引用,不会在交易的output侧出现,UTXO依然保持精简,同时可以把手续费负担转嫁给接收方。既然所述的输出脚本好处很多,那我们是否有办法让这种交易方式变得安全呢?这就需要讲讲什么是P2SH了。比特币核心开发者GavinAdresen提出了一种叫做PaytoScriptHash(P2SH)的技术。P2SH的交易输出依然是判断Hash160(Script)==<ScriptHash>,这里Script就是上文中提到的Pre-image但是在判断完毕后又增加了一个步骤:使用比特币脚本执行器再次运行Script本身。比特币开发者为这类交易创建了特殊的地址,用3作为开头,地址生成规则为:Base58(0x05+<ScriptHash>+Checksum)这样事情就变得有趣了,在前P2SH时代Script仅仅作为Hash160的原象存在,但是一旦激活了P2SH,Script必须要求是一段有意义、可执行的比特币脚本。我们可以在Script中加入数字签名检查的指令,或者多重签名检查功能,甚至智能合约都可以在P2SH的基础上进行开发,既使用了强大的比特币脚本,又能让交易保持精简。并且由于P2SH交易地址中只存有ScriptHash,相当于保险箱上只有Hash。在交易被成功花费之前,任何人都无法知晓Script内容,很好的保护了隐私。P2SH在2012年4月1日激活,开启了比特币的P2SH时代现在全世界的3-类保险箱经过了升级,再也不怕钥匙被复制了,因为保险箱的钥匙会内置芯片。升级后的保险箱除了能够校验钥匙形状,更能读取钥匙中内置的芯片的数据,芯片中的内容会影响钥匙的形状。Bob制作了一个能够校验钥匙芯片中数字签名的保险箱,让Alice把钱放进这个保险箱然后锁起来。Bob开启保险箱的钥匙形状虽然可以被复制,但是这把钥匙内置了芯片,芯片中可以包含各种高级约束条件,保证钥匙不会被越权滥用。保险箱会在校验完形状后,会执行钥匙芯片内的程序查有效性,只有两个检查都通过才能开启保险箱。被锁死的币是否有挽回可能
再回到开头的那个问题,zer0to0ne遇到的钱包错误锁死资产的事故,能否采用1-地址的钥匙去开启3-保险箱,挽救保险箱中的资产呢?这个问题可以解释为:Alice按照Bob的要求制作了一个3-类保险箱,但是这个保险箱是被pywallet错误修改的,实际上Bob的本意是需要一个1-类保险箱,因为Bob手里只有一个1-类保险箱的钥匙。当Bob请求Alice把比特币锁定到3-类保险箱时,这个保险箱就需要同时校验钥匙形状和钥匙芯片内容了,但是Bob的1-类保险箱的钥匙形状是PublicKey决定的,在保险箱误变为3-类保险箱后,钥匙形状校验却没有改变,也没有相应的钥匙芯片内容。Bob尝试在钥匙芯片中写入PublicKey,使得钥匙形状和锁匹配,但是芯片中的PublicKey却无法被保险箱正确执行,所以Bob可能再也无法将他的比特币从保险箱中解锁了。SegWit——全新时代来临
比特币开核心发者EricLombrozo,JohnsonLau,PieterWuille提出来了一种全新的概念,隔离见证。这是一种有效缓解比特币区块拥堵的技术,并且彻底解决了交易延展性问题。在SegWit升级之前,每一个用完的钥匙都插在保险箱上,钥匙占据了一定的体积导致仓库无法密集堆积这些用完的保险箱,总是要为了露在外面一大截的钥匙腾空间。那我们想想能不能把钥匙体积减小,并且用足够廉价的材料来制作,节约成本。于是便有了隔离见证,它干脆直接把锁从保险箱上移走,变成一个远程无线校验的保险箱,用户可以把钥匙统一插在远离保险箱的地方来远程开启对应的保险箱。2017年08月24日,SegWit软分叉被正式激活,结束了旷日持久的矿工开发者对峙为了兼容3-类保险箱,比特币开发者使用了一种叫做P2SH-P2WPKH的技术,即通过P2SH来包裹P2WPKH交易,让P2WPKH交易可以过不支持SegWit的老旧节点。还有一种类似P2SH包裹的P2WSH技术,在此不多做介绍。我们先来解释一下P2WPKH是什么:P2WPKH全称PaytoWitnessPublicKeyHash,相较于P2PKH,P2WPKH把scriptSig移动到交易外部,节省了占用的区块空间。为了向前兼容未及时升级的比特币节点,这个P2SH需要如何构造呢?Bob首先产生一个P2PKH地址,从地址中解析出PubKeyHash,然后构造一个这样的脚本:Script=0x0014+<PubkeyHash>然后计算Script的Hash160得到ScriptHash,构造出一个3地址:Base58(0x05+<ScriptHash>+Checksum)当Alice把币锁定到Bob提供的<ScriptHash>中,意味着Bob需要提供正确的Script才能解锁。Bob通过构造有效的Script通过了Hash160检查,即成功的通过了钥匙形状检查,并且钥匙里的程序也能被保险箱正确解析并执行。细心的读者应该又发现了问题,这个钥匙却少了相关安全性约束,很容易被复制,矿工有机会将交易篡改,把币转给Eve。但是升级了SegWit之后,支持SegWit的比特币节点会在校验P2SH后再额外地校验Bob的签名是否正确,数字签名作为独立于交易之外的安全约束,不再占用宝贵的区块空间。zer0to0ne:SegWit为比特币扩容做出了贡献的同时,也同时在保持向前兼容性上面付出了一些代价。在原生SegWit交易被广泛采用之前,使用了混乱的P2SH兼容技术。如果未来比特币全部统一到bc1-地址,那么就可以彻底避免使用P2SH包裹技术,并且最大限度地利用区块容量。对三个问题的回复
比特币地址有1打头地址,也有3打头的地址,你知道这两者有什么区别吗?1-地址是用做P2PKH交易的目标地址,而3-地址是用作P2SH,SegWit交易的目标地址。在哪种情况下,地址上的比特币会被锁死?假设一个比特币地址为3-地址,如果世界上没有人能够提供一个可以通过Hash160校验并有效可执行的脚本,那么这个地址上的比特币会被锁死。到底是谁拥有比特币的控制权,是你?还是你在使用的钱包?如果一个比特币地址为1-地址,那么该地址上的比特币被锁在一个1-类保险箱中,拥有私钥的用户拥有该地址上的比特币。这里请注意“拥有私钥”有两层含义:自己牢记私钥,其他人无从知晓。如果一个比特币地址为3-地址,那么在某个用户披露一个“解锁脚本”之前,没人知道该地址上的比特币归属。因为脚本由钱包来生成的,而用户只“拥有私钥”,如果你不知道地址对应的脚本,就相当于交出了地址控制权。脚本的内容才真正决定了比特币的归属。
郑重声明: 本文版权归原作者所有, 转载文章仅为传播更多信息之目的, 如作者信息标记有误, 请第一时间联系我们修改或删除, 多谢。