是谁控造了比特币,是你?仍是钱包?——BTC地址与交易原理大分析

刚刚阅读1回复0
kewenda
kewenda
  • 管理员
  • 注册排名1
  • 经验值163605
  • 级别管理员
  • 主题32721
  • 回复0
楼主

是谁控造了比特币,是你?仍是钱包?——BTC地址与交易原理大分析

比特币地址有 1 打头地址 ,也有 3 打头的地址,那两者有什么区别吗?

在哪种情况下,地址上的比特币会被锁死?

到底是谁拥有比特币的控造权,是你?仍是你的钱包?

若是你在利用比特币钱包,但却无法答复上面三个问题,那么那篇文章是为你而写。

安比(SECBIT)尝试室在对数字钱包源码审计时,发现一个名为 pywallet 的比特币钱包开源库包罗了一个严峻缺陷。若是向 pywallet 生成的 OmniLayer 收款地址转账,将招致资产永久丧失。

据安比(SECBIT)尝试室区块链手艺专家 zer0to0ne 解释,OmniLayer 协议允许在比特币区块链上发行自定义资产(好比 USDT)。OmniLayer 资产交易的素质是比特币交易。比特币交易的代码库有良多,pywallet 即是此中一种。它能够便利的构造契合 OmniLayer 格局的比特币交易。目前 pywallet 已经被应用在一些数字钱包软件中。

但是,开源库 pywallet 在生成 OmniLayer 钱包地址的时候,误将地址的前缀写反了,若干资产被锁死在无效的地址内!

下面是 pywallet 相关错误代码截图:

文件地址:https://github.com/ranaroussi/pywallet/commit/eb784ea4dd62fe2a50e1352e7d24438fc66a4ac0#diff-ca3a8be6f2ab4be3bfd69a49f5f4122a

插队科普一下:比特币收集上最常见的地址类型有三种:通俗公钥地址(1-地址),脚本哈希地址(3-地址)和隔离见证地址(bc1-地址),地址类型通过地址的前缀来区分。此中1-地址的前缀为 0x00,3-地址 的前缀为 0x05。

1-地址:那是最常见的比特币地址,凡是用于通俗转账收款。1-地址 现实上为公钥Hash的编码。验证 1-地址的签名后即可解锁收款。3-地址:那个地址为脚本(Script)哈希地址。那类地址现实对应为一段比特币脚本Hash的编码。bc1-地址:bech32编码地址,用于隔离见证交易。

开源库 pywallet 倒置了地址前缀,将 1-地址 错误地设置为 3-地址。因而本来要转给 1-地址 的资产会误转入 3-地址。当账户持有者以 1-地址 的验证体例,也就是私钥签名去取出资产的时候,区块链收集却以 3-地址 施行脚本的体例去施行验证,招致用户无法一般取出资产!

请稳重利用 pywallet 开源库!!

本相:比特币从未实正实现过转账功用

那一点出乎良多人的意料,因为比特币的实现基于 UTXO 模子,与我们曲不雅理解的账户模子纷歧样。zer0to0ne 解释说,现实上比特币从未实正实现过凡是意义上的转账功用。中本聪只给比特币设想了一系列比特币脚本操做符和比特币脚本施行器,而所谓的转账过程现实是由一段比特币脚本锁定、解锁过程来模仿。那与日常生活中的账本概念(或称之为账户模子)纷歧样。

为了便于理解,我们能够把比特币区块链上的资产交易比方成 将资产锁进保险箱,只要持有保险箱钥匙的人(即收款人)才气拿出保险箱中的资产停止交易。举个例子,若是 Alice 要向 Bob 付出一笔资产,Alice 将那笔资产锁进一个保险箱中,只要 Bob 才有那个保险箱的钥匙,即只要Bob才气取出那笔资产。若是 Bob 要取出资产,那么要求 Bob 必需同时花掉那笔资产(即锁入另一个保险箱)。在 Bob 没有取出资产前,资产其实不实正属于 Bob。设想若是 Bob 丢了钥匙,那么将无法再取出资产。 换句话说,那笔资产还在保险箱中保留的时候,既不属于Alice,也不完全属于Bob。当然,Alice 也能够把资产放入任何人都能够翻开的保险箱中,那也被称之为 Anyone-Can-Spend 交易。

因为比特币区块链上的收款地址差别,保险箱的类型也有所差别。差别类型的保险箱需要差别类型的钥匙来开启。付款报酬收款人定造一个保险箱,将资产放入保险箱中并上锁,再将保险箱丢到公共场合。而保险箱有两种开启办法:

若收款报酬 1-地址,我们称保险箱为1-类保险箱 。而响应的钥匙必需是指定收款地址对应的私钥。解锁保险箱的过程也就是验证 1-地址公钥以及公钥对应的数字签名,那也是我们凡是所理解的向通俗账户地址转账的验证过程。若收款报酬 3-地址,我们称为3-类保险箱 。开启钥匙必需为一段能够施行的比特币脚本。解锁保险箱的过程是:比特币脚本的Hash值对应到 3-地址 ,同时比特币脚本施行器运行该脚本后胜利返回。也就是说只要拥有脚来源根基文并能够胜利施行的人才能够提取那个保险箱里的资产。

回到那一节的问题:为什么说比特币从未实现实正意义上的转账功用。谜底很简单,因为比特币系统中底子就不存在账户的概念,账户之间的转账也无从谈起。一小我能在将来翻开几个保险箱,也是未知数。

通过上面的解释,我们可知:当 pywallet 开源库误将 1-地址 识别为 3-地址 时,就仿佛将本来的1-类保险箱 革新成了3-类保险箱,而账户持有者仍是拿着 1-类保险箱 的钥匙去解锁,那么天然无法翻开保险箱。那么之前 zer0to0ne 发现的被误锁住的 OmniLayer 数字资产能否能恢复?

能否存在一种可能性,接纳 1-地址 的钥匙去开启 3-保险箱 ?

zer0to0ne 接着向我们详细解释了两个重要概念 P2PKH(Pay to Public Key Hash) 与 P2SH (Pay to Script Hash)的前因后果。那两个名词别离代表了两种差别的比特币交易类型。

下面是 zer0to0ne 的出色手艺细节阐发

P2PKH——中本聪的伟大创造

Pay to Public Key Hash 望文生义,是将比特币放入一个保险箱,钥匙孔为公钥 Hash(Public Key Hash)。我们最常见到的 1-地址 素质上就是 Public Key Hash 的一种编码。1-地址 的生成过程也很简单,将公钥颠末Hash160运算得到 Public Key Hash,在 Public Key Hash 头部补上前缀 0x00,Hash 尾部补上校验和,颠末Base58便得到了1开头的比特币地址。

Base58(0x00 + <Public Key Hash> + Checksum)

我们来看看P2PKH交易类型的保险箱构造过程,Alice发送比特币给Bob为例:

付款方 Alice 在构造保险箱的时候需要设置一个锁定脚本:

OP_DUP ​ OP_HASH160 ​ (Bob收款地址蕴含的Public Key Hash) ​ OP_EQUALVERIFY ​ OP_CHECKSIG ​

注:我们能够把那一步理解为 Alice 为 Bob 定造了一个保险箱,把比特币放入保险箱并用 Bob 的公钥 PubKey Hash上锁。如今那把锁除了持有私钥的 Bob,谁都无法翻开。

当 Bob 需要破费 Alice 给他的比特币时,需要供给需要的参数:交易签名 + 公钥(手艺黑话:scriptSig)来开启保险箱,使得锁定脚本施行后返回 True,那一步凡是由钱包主动完成。

我们来看看比特币节点是若何校验 scriptSig 合法性的。

(图片来自Mastering Bitcoin)

脚本施行过程如图所示,Bob将交易签名后得到的数据(现实上还要包罗数据长度信息),实正的scriptSig 应该为<sig len> <sig> <pubKey len> <pubKey>,比特币脚本施行器从 PUSH 数据起头,PUSH 操做会读取第一个字节获取将要入栈的数据长度信息,然后持续施行比特币脚本,曲到最初施行完毕查抄施行成果。

起首入栈的是 <sig>,然后将 <PubK> 入栈,一次DUP操做将在栈顶复造一份 <PubK>,HASH160弹出栈顶的<PubK> 并计算Hash,将成果压回栈中,之后利用 EQUALVERIFY 弹出Hash比照能否和 <PubKHash>相等,若是相等则返回True,不相等便标识表记标帜交易为无效。施行到那一步,表露了公钥,确保了签名者的身份的准确性,但是黑客或矿工能够通过表露的公钥构造出一个新的交易替代原始交易,无法包管平安,那么便需要下一步来包管交易无法伪造。此时栈上还有 <PubK> 和 <sig>,施行 CHECKSIG,将校验数字签名的准确性,确保了签名者拥有地址对应的私钥。

数字签名除了持有私钥的人,谁也无法伪造,施行至此,一笔比特币P2PKH交易已经平安地完成了。

再解释一遍:当 Bob 要破费 Alice 给他的比特币时,Bob 只要用准确的钥匙才气翻开 Alice 留给他的保险箱,把钱放入 Bob 新构造的一个保险箱里。

那时候一些伶俐的读者会留意到一个细节:若是 Bob 取出钥匙,在还未翻开保险箱的时刻,区块链上的任何矿工都能看得见那把钥匙的外形,理论上他们是能够立即复造一把钥匙,把 Alice 留给 Bob 的保险箱翻开并花掉(俗称 Front-running 攻击)。实的能够如许做吗?显然中本聪考虑了那个问题,那把钥匙中的交易签名是 Bob 倡议的交易的完好签名。假设 Bob 要将 Alice 构造的保险箱中的比特币 拆入一个新的保险箱(留给Charlie),那时候 Bob 出示的钥匙包罗了 Charlie 的公钥Hash,矿工固然能够复造 Bob 的钥匙,但是那把钥匙已经隐藏了下一个新保险箱的关键信息,因而矿工无法利用那个复造钥匙来完成此外动做(无法调用数字签名)。

P2SH——后中本聪时代的严重立异

中本聪设想了一个那么强大的脚本系统,只用来构造转账交易似乎太浪费了,我们尝尝用其他指令构造一些出格的锁定脚本,并利用其他体例来解锁。

例如我们能够构造一个用 Hash 原象(Pre-image)来解锁交易的脚本:

OP_HASH160 <Hash> OP_EQUAL

那个脚本的含义是:当满足 Hash160(Pre-image)==<Hash>那个前提时,即可胜利将脚本解锁。

我们继续通过保险箱的例子来解释,并给那类保险箱起名为 3-类保险箱。如今 Alice 给 Bob 的比特币锁定在一个由上述 Hash160庇护的保险箱里,我们姑且称之为哈希锁吧。

那把锁仍然需要准确的外形才气开启,但是平安性却弱良多,贫乏数字签名机造招致钥匙隐藏的关键信息不会跟着Bob 新建的保险箱而变革。任何矿工都能在 Bob 亮出钥匙的一霎时复造出一摸一样的钥匙,抢着去开Alice留给Bob的保险箱(Front-running),将币转给另一小我 Eve,于是本来属于 Bob 的比特币会被洗劫一空。

固然那个脚本十分不平安,但是它却有两个十分奇异的功用:

交易构造的输出足够短,意味着比特币节点维护的 UTXO 缓存占用空间将会大大减小Pre-image 老是在交易被破费时做为 input 来引用,不会在交易的 output 侧呈现,UTXO仍然连结精简,同时能够把手续费承担转嫁给领受方。

既然所述的输出脚本益处良多,那我们能否有法子让那种交易体例变得平安呢?那就需要讲讲什么是 P2SH了。

比特币核心开发者 Gavin Adresen 提出了一种叫做 Pay to Script Hash (P2SH) 的手艺。

P2SH 的交易输出仍然是判断 Hash160(Script)==<Script Hash>,那里Script 就是上文中提到的 Pre-image 但是在判断完毕后又增加了一个步调:利用比特币脚本施行器再次运行 Script 自己。

比特币开发者为那类交易创建了特殊的地址,用 3 做为开头(0x05颠末 Base58 编码后变成 3),地址生陈规则为:

Base58(0x05 + <Script Hash> + Checksum)

如许工作就变得有趣了,在前 P2SH 时代 Script 仅仅做为 Hash160 的原象存在,但是一旦激活了P2SH,Script 必需要求是一段有意义、可施行的比特币脚本。

我们能够在 Script 中参加数字签名查抄的指令,或者多重签名查抄功用,以至智能合约都能够在P2SH的根底长进行开发,既利用了强大的比特币脚本,又能让交易连结精简。而且因为 P2SH 交易地址中只存有 Script Hash,相当于保险箱上只要 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-类保险箱 的钥匙外形是 Public Key 决定的,在保险箱误变成 3-类保险箱 后,钥匙外形校验却没有改动,也没有响应的钥匙芯片内容。

Bob 测验考试在钥匙芯片中写入Public Key,使得钥匙外形和锁婚配,但是芯片中的Public Key 却无法被保险箱准确施行,所以 Bob 可能再也无法将他的比特币从保险箱中解锁了。

SegWit——全新时代降临

比特币开核心发者 Eric Lombrozo, Johnson Lau, Pieter Wuille 提出来了一种全新的概念,隔离见证(Segregated Witness,简称SegWit)。那是一种有效缓解比特币区块拥堵的手艺,而且彻底处理了交易延展性问题(Transaction Malleability)。

在SegWit晋级之前,每一个用完的钥匙都插在保险箱上,钥匙占据了必然的体积招致仓库无法密集堆积那些用完的保险箱,老是要为了露在外面一大截的钥匙腾空间。那我们想想能不克不及把钥匙体积减小,而且用足够廉价的质料来造做,节约成本。

于是便有了隔离见证(Segregated Witness简称SegWit),它痛快间接把锁从保险箱上移走,酿成一个长途无线校验的保险箱,用户能够把钥匙同一插在远离保险箱的处所来长途开启对应的保险箱。

2017年08月24日,SegWit软分叉被正式激活,完毕了旷日耐久的矿工开发者对峙

为了兼容3-类保险箱,比特币开发者利用了一种叫做P2SH-P2WPKH的手艺,即通过P2SH来包裹P2WPKH交易,让P2WPKH交易能够骗过不撑持SegWit的老旧节点。还有一品种似P2SH包裹的P2WSH手艺(P2SH-P2WSH),在此不多做介绍。

我们先来解释一下P2WPKH是什么:

P2WPKH全称Pay to Witness Public Key Hash,相较于P2PKH,P2WPKH把scriptSig挪动到交易外部,节省了占用的区块空间。

为了向前兼容未及时晋级的比特币节点,那个P2SH需要若何构造呢?

Bob起首产生一个P2PKH地址,从地址中解析出PubKey Hash,然后构造一个如许的脚本:

Script = 0x0014 + <Pubkey Hash>

然后计算Script的Hash160得到Script Hash,构造出一个3地址:

Base58(0x05 + <Script Hash> + Checksum)

当 Alice 把币锁定到 Bob 供给的 <Script Hash> 中,意味着 Bob 需要供给准确的 Script 才气解锁。

Bob通过构造有效的Script通过了Hash160查抄,即胜利的通过了钥匙外形查抄,而且钥匙里的法式也能被保险箱准确解析并施行。

细心的读者应该又发现了问题,那个钥匙却少了相关平安性约束,很容易被复造,(Front-running)矿工有时机将交易窜改,把币转给 Eve。

但是晋级了 SegWit 之后,撑持 SegWit 的比特币节点会在校验 P2SH 后再额外埠校验Bob的签名能否准确,数字签名做为独立于交易之外的平安约束,不再占用贵重的区块空间。

zer0to0ne:

SegWit 为比特币扩容做出了奉献的同时,也同时在连结向前兼容性上面付出了一些代价。在原生 SegWit 交易被普遍接纳之前,利用了紊乱的 P2SH 兼容手艺。若是将来比特币全数同一到 bc1-地址 ,那么就能够彻底制止利用 P2SH 包裹手艺,而且更大限度天时用区块容量。对三个问题的回复比特币地址有 1 打头地址 ,也有 3 打头的地址,你晓得那两者有什么区别吗?

1-地址 是用做 P2PKH 交易的目的地址,而 3-地址 是用做 P2SH,SegWit交易的目的地址。

在哪种情况下,地址上的比特币会被锁死?

假设一个比特币地址为 3-地址 ,若是世界上没有人可以供给一个能够通过Hash160校验并有效可施行的脚本,那么那个地址上的比特币会被锁死。

到底是谁拥有比特币的控造权,是你?仍是你在利用的钱包?

若是一个比特币地址为 1-地址 ,那么该地址上的比特币被锁在一个 1-类保险箱 中,拥有私钥的用户拥有该地址上的比特币。那里请留意“拥有私钥”有两层含义:(1)本身服膺私钥,(2)其别人无从晓得。

若是一个比特币地址为 3-地址 ,那么在某个用户披露一个“解锁脚本”之前,没人晓得该地址上的比特币归属。因为脚本由钱包来生成的,而用户只“拥有私钥”,若是你不晓得地址对应的脚本,就相当于交出了地址控造权。脚本的内容才实正决定了比特币的归属。

0
回帖 返回旅游

是谁控造了比特币,是你?仍是钱包?——BTC地址与交易原理大分析 期待您的回复!

取消
载入表情清单……
载入颜色清单……
插入网络图片

取消确定

图片上传中
编辑器信息
提示信息