从BTC地址与交易道理看谁操纵了比特币

比特币地址有 1 打头的地址 ,也有 3 打头的地址,这二者有甚么区分吗?

在哪一种环境下,地址上的比特币会被锁死?

到底是谁具有比特币的操纵权,是你?还是你的钱包?

若是你在利用比特币钱包,但却没法回答上面三个题目,那末这篇文章是为你而写。

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

据安比(SECBIT)尝试室区块链技术专家 zer0to0ne 解释,OmniLayer 和谈许可在比特币区块链上发行自定义资产(比如 USDT)。OmniLayer 资产交易的本质是比特币交易。比特币交易的代码库有很多,pywallet 便是此中一种。它可以方便的构造符合 OmniLayer 格式的比特币交易。今朝 pywallet 已被利用在一些数字钱包软件中。

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

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

是谁控制了比特币?BTC地址与交易原理大剖析

文件地址: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 + + Checksum)

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

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

OP_DUPOP_HASH160(Bob收款地址包含的Public Key Hash)OP_EQUALVERIFYOP_CHECKSIG

注:我们可以把这一步理解为 Alice 为 Bob 定制了一个保险箱,把比特币放入保险箱并用 Bob 的公钥 PubKey Hash上锁。此刻这把锁除了持有私钥的 Bob,谁都没法打开。

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

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

(图片来自Mastering Bitcoin)

脚本履行过程如图所示,Bob将交易签名后得到的数据(现实上还要包含数据长度信息),真实的scriptSig 应当为 ,比特币脚本履行器从 PUSH 数据开始,PUSH 操纵会读取第一个字节猎取将要入栈的数据长度信息,然后持续履行比特币脚本,直到最后履行终了检查履行结果。

起首入栈的是 ,然后将 入栈,一次DUP操纵将在栈顶复制一份 ,HASH160弹出栈顶的 并计算Hash,将结果压回栈中,以后利用 EQUALVERIFY 弹出Hash对比是不是合相等,若是相等则返回True,不相等便标记交易为无效。履行到这一步,暴露了公钥,确保了签名者的身份的准确性,但是黑客或矿工可以经由过程暴露的公钥构造出一个新的交易替代原始交易,没法保证安全,那末便需要下一步来保证交易没法捏造。此时栈上还有 和 ,履行 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_HASH160OP_EQUAL

这个脚本的含义是:当知足 Hash160(Pre-image)==这个前提时,便可成功将脚本解锁。

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

这把锁仍然需要准确的外形才能开启,但是安全性却弱很多,贫乏数字签名机制导致钥匙埋没的关键信息不会跟着Bob 新建的保险箱而变化。任何矿工都能在 Bob 亮出钥匙的一刹时复制出一摸一样的钥匙,抢着去开Alice留给Bob的保险箱(Front-running),将币转给另外一个人 Eve,因而本来属于 Bob 的比特币会被洗劫一空。

固然这个脚本非常不安全,但是它却有两个非常奇异的功能:

1. 交易构造的输出足够短,意味着比特币节点保护的 UTXO 缓存占用空间将会大大减小

2. Pre-image 老是在交易被花费时作为 input 来援用,不会在交易的 output 侧出现,UTXO仍然保持精简,同时可以把手续费负担转嫁给接收方。

既然所述的输出脚本好处很多,那我们是不是有办法让这类交易方式变得安全呢?这就需要讲讲甚么是P2SH了。

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

P2SH 的交易输出仍然是判定 Hash160(Script)==

本文系转载自其它媒体或授权刊载,目的在于信息传递,并不代表本站赞同其观点和对其真实性负责,如有新闻稿件和图片作品的内容、版权以及其它问题的,请联系我们。