BIP 标准

比特币改进建议(Bitcoin Improvement Proposal, BIP)是 Amir Taaki 在2001年的 BIP-0001 中提出,由 Luke Dash Jr. 在 BIP-0002 中对该标准进行了扩展[1]

BIP stands for Bitcoin Improvement Proposal. A BIP is a design document providing information to the Bitcoin community, or describing a new feature for Bitcoin or its processes or environment. The BIP should provide a concise technical specification of the feature and a rationale for the feature.

BIP 代表比特币改进提案。BIP是向比特币社区提供信息的设计文档,或描述比特币或其流程或环境的新功能。BIP 应提供该功能的简明技术规范和功能的基本原理。

本文主要着重深入对闪电网络和 Trao 资产的研究,于是这里只会提及相关的部分标准。

地址标准

截止到今天,比特币区块链有四种不同的地址标准,分别是遗留(Legacy)地址,支付脚本哈希(Pay to Script Hash, P2SH)地址,隔离见证(SegWit)地址,主根(Taproot)地址[2]。在本文中,和 Trao 资产最为相关的是最后一种地址 —— Traproot。

Legacy

Legacy 地址也被称为传统地址,它是比特币区块链诞生开始就使用的地址。这样的地址以1开头,其生成流程如下

Legacy(4)

依据 BIP-0032 (公钥分层推导标准)BIP-0044 (派生路径标准),一个私钥可以对应派生出不同的公钥,由此也可以通过一个私钥管理多个地址。

由于在这里地址的生成过程中使用到了对公钥的哈希,这样的地址类型也被称为向公钥哈希支付(Pay to Public Key Hash, P2PKH)。这样的交易方式下,发送方需要在发送交易时嵌入 PubKey 脚本以将比特币发送给目标地址[3]

P2SH

P2SH 是另外一种地址类型,它被称为“向脚本支付”,从名称上就已经决定了这样的地址的使用方式和 Legacy 地址的不同,其地址以 3 开头。P2SH 是在 BIP-0016 中被提出,它被提出的动机是:

The purpose of pay-to-script-hash is to move the responsibility for supplying the conditions to redeem a transaction from the sender of the funds to the redeemer.

The benefit is allowing a sender to fund any arbitrary transaction, no matter how complicated, using a fixed-length 20-byte hash that is short enough to scan from a QR code or easily copied and pasted.

该标准定义了新的交易类型,使得提供花费UTxO所需的条件和责任由发送者转移到了接收者。先说说 BIP-0012:

而 P2SH 类型的地址是在 BIP-0013 中提出,在此之前提出的 BIP-0012 中为了实现 P2SH 而尝试将预留的 OP_NOP1 操作码定义为新的 OP_EVAL 操作码,该操作码的功能是从栈顶弹出一个对象,对它反序列化后得到一个脚本代码,然后执行该脚本代码。但是该操作码在实现时没有准确地限制脚本语言运行时的栈的深度,这会导致执行脚本的节点在这里进入死循环,于是这一次软分叉在上线之前被放弃。

O’Connor 在 https://github.com/bitcoin/bitcoin/issues/729 提出了这一漏洞:

在 OP_EVAL 的处理代码中,有这样一段代码:

1
if (!EvalScriptInner(stack, subscript, txTo, nIn, nHashType, pbegincodehash, pendcodehash, nOpCount, nSigOpCount, fStrictOpEval, nRecurseDepth++))

nRecurseDepth++ 返回的是变量未递增的值,这会导致执行该操纵码时不会限制递归的深度。

P2SH 类型的地址和 P2PKH 类型的地址生成过程是一样的,不同的地方在于最后进行 Base58-Check 的输入:

image-20230531220559720

P2SH 定义了新的交易输出的类型,它在 scriptPubKey 中定义了新的脚本:

1
[OP_HASH160][ScriptHash][OP_EQUAL]

这使得发送者只需要在输出中指定使用该输出的发送方所提供的脚本需要满足的条件(脚本代码的hash对应),这样就将进行交易时的费用转移到了接收方而不是发送方,具体的实现原理见 How does P2SH work? - learn me a bitcoin 以及脚本语言执行过程 Script -A mini programming language

SegWit

SegWit 是隔离见证(Segregated Witness),隔离见证是一系列的 BIP 标准组成的:

隔离见证的用意是优化比特币交易和区块结构,将交易的签名(scriptSig)从交易中移到另外一个独立的结构中。

首先考虑比特币交易中的签名,对于 Pay-to-PubKey-Hash 交易,它的输出中的 scriptPubKey 脚本格式如下

1
[OP_DUP][OP_HASH160][PUBLIC_KEY][OP_EQUALVERIFY][OP_CHECKSIG]

这部分脚本被称为锁定脚本,结合输入中的 scriptSig 形成一段脚本,由矿工在进行交易打包时进行验证,其具体的过程见How does P2PKH work?

而进行隔离见证后,锁定脚本变为

1
[VERSION][PUBLIC_KEY]

在具有隔离见证功能的客户端上,只需要将两个值压栈,第一个数字上版本号,而第二个值是锁定脚本,而在 BIP - 0143 中,规定了隔离见证的输出应该使用压缩公钥的哈希值来进行创建

同样地,在原有的另外一种交易类型 P2SH 下,锁定脚本中存放的是一个叫脚本的哈希值,尝试花费这笔 UTxO 的使用者需要提供满足哈希值的签名/口令来使用,在隔离见证后,输出的锁定脚本变为如下所示,这里进一步地减少了输出中的数据量

1
[VERSION] [SCRIPT_HASH]

而在隔离见证下,交易的结构中多了一个 witness 字段,解锁 UTxO 的解锁脚本被存放在这一字段下

另外,为了进一步支持隔离见证交易,对于 SigWit 类型的交易的交易费用会进行“打折”,它原来的交易大小不变,但是在隔离见证下引入的“虚拟大小”比正常的交易更低

Taproot

Taproot,翻译为中文是“主根”。

A taproot is a large, central, and dominant from which other roots sprout laterally.

比特币区块链的 Traproot 升级由三个 BIP 标准组成:BIP-0340 (Schnorr 签名)BIP-0341 (Traproot)BIP-0342 (TapScript)

其中,BIP-0340 中引入了 Schnorr 签名,该签名方案的最大好处是可以聚合签名,它能够使得多位签名整合到一起,从而节省空间[7]

MAST

BIP-0341 中引入了默克尔抽象语法树(Merklized Abstract Syntax Tree, MAST)[15][16][17],其目的是隐藏 UTxO 的支出条件,并且减少信息的大小。这是 Taproot 升级的一部分,Taproot 升级将原有的 P2SH(Pay-to-Script-Hash) 和 P2PKH(Pay-to-Public-Key-Hash)结合在一起,使得一笔数输出可以直接通过私钥使用,也可以提供花费输出的脚本和默克尔证明来使用。

MAST 结合了抽象语义树和默克尔树,默克尔树作为一种在区块链中常见的数据结构,在这里不再进行赘述。而抽象语法树(AST)是一种把程序分割为独立的小块以描述程序的方法,这样会让程序变得容易分析和优化,具体可查阅Abstract syntax tree。MAST 结合了 AST 的将程序划分为多个小块的思想,再把程序每个小块进行哈希,利用默克尔哈希树的思想把这些哈希结果构建为默克尔树。

image-20230910202902204

考虑这样一个脚本[17]:Alice 希望可以随时花费她的比特币,但是如果她连续三个月没有花费,那么她的兄弟姐妹 Bob 和 Charlie 就可以花费这笔 UTxO,其脚本实现如下

1
2
3
4
5
6
OP_IF
<Alice's pubkey> OP_CheckSig
OP_ELSE
"3 months" OP_CSV OP_DROP
2 <Bob's pubkey> <Charlie's pubkey> 2 OP_CHECKMULTISIG
OP_ENDIF

在 P2SH 下,这样的脚本是需要在花费时完全暴露在交易中的,Alice 在花费这笔 UTxO 的同时需要提供该脚本,以及包含在其中的 Bob 和 Charlie 的公钥

而在有了 MAST 后,对该脚本的两个条件进行划分,得到一个简单的 MAST

image-20230910202920105

此时,Alice 在花费的时候只需要选择提供她的公钥验证脚本和 Hash2 作为默克尔证明即可,而不需要暴露 Hash 2 下的具体脚本,这部分信息不会上链。而这样也进一步降低了类似交易的开销,这是很自然的,提供完整的脚本总是比提供脚本的哈希值的数据量少。而这样的结构也给智能合约的实现提供了可能,这样的方式正如 EVM 中的字节码一样,在运行前可以根据输入数据的前4个字节来选取将要调用的函数。不同地方在于,这样的脚本调用需要用户提供具体的脚本,以及默克尔证明来证明脚本是合法的。

多重签名与PSBT

多重签名

多重签名正如其名字一样,一笔交易需要两个或者更多的签名才能生效,多重签名也被称为 n-of-m 交易,指该交易需要 $m$ 个签名者下的至少 $n$ 个签名才能生效

它的脚本形式是

1
n [PUBLIC_KEY] [PUBLIC_KEY] [PUBLIC_KEY] ... [PUBLIC_KEY] m CHECKMULTISIG

如果使用 P2PKH 的交易形式来实现多重签名,就需要发送交易的交易方来指定该脚本,并且输入一系列的签名者公钥匙,于是出现了 P2SH 来指定脚本哈希,使得这部分输入输入所产生的开销转移到了使用者

PSBT

PSBT 是在 BIP-0174 中所提出的标准,它被用来协助未签名交易(unsigned transactions)的传输

它可以允许多个签名者并行地对交易进行签名,然后再将交易组装为合成一个完整的 PSBT,目前 Ordinals 相关的交易平台的 Bid 和 Offer 就是利用了 PSBT 来实现

而 PSBT 也可以被用于实现多重签名

Ordinals

序数理论

序数是一种比特币的编号方案,这是的跟踪和转移单个 sat 成为可能[13],它按照每个比特币被挖掘出的顺序以及交易时根据先入先出的规则来进行编号

序数的表示方式:

  • 整数符号:2099994106992659 这个序号是根据挖掘聪的顺序分配。
  • 十进制符号:3891094.16797,第一个数字是挖掘聪的区块高度,第二个数字是区块内聪的偏移量。
  • 度数符号:3°111094′214″16797‴,具体的度数表示原理见序数理论手册[13]
  • 百分数符号:99.99971949060254%。以百分比表示聪在比特币供应中的位置。
  • 名字:satoshi(聪)。使用字符a到z对序号进行编码。

铭刻

铭文的铭刻利用了隔离见证后的特性[12],即将见证脚本放入到交易本身之外的一个 witness 字段中,使用隔离见证的交易只需要 20% 的交易费用

铭文的相关内容被放入到脚本中,例如

1
2
3
4
5
6
7
8
OP_FALSE
OP_IF
OP_PUSH "ord"
OP_1
OP_PUSH "text/plain;charset=utf-8"
OP_0
OP_PUSH "Hello, world!"
OP_ENDIF

在这里,OP_1 指示下一次压入包含内容类型,OP_0 指示后续数据压入包含内容本身

开头的 OP_FALSE 指令入栈后脚步立刻停止,但是由于隔离见证的特性,这部分数据依然在链上存在,所以 Ordinals Inscription 的本质是在比特币上借助这样一个用于不能被执行的脚步来实现一个记账的功能

所以,铭文的索引只能高度依赖链下的中心化索引,这样铭刻的一个铭文在链下会被记录到对应输出的第一个聪上,在 ordinals.com 中可以看到每个聪的相关信息,以及它是否存在铭刻的数据,目前索引这些铭文(Ordinals Inscription)的程序在 https://github.com/ordinals/ord 维护

例如 inscription#0,它被铭刻在了序数为 1252201400444387 的聪上

闪电网络

闪电网络是建立在 Bitcoin 上的 Layer 2 解决方案,其目的是在 Bitcoin 的支付场景下帮助用户节省成本、提高效率。而闪电网络所依赖的思想也很简单,即构建资金池,这样的资金池也被称为交易双方的微支付通道。更具体一点,涉及到两个核心概念:

  • Revocable Sequence Maturity Contract(RSMC):序列到期可撤销合影
  • Hashed Timelock Contract(HTLC):哈希时间锁定合约

RSMC 假定了交易双方之间存在一个微支付通道,双方先存放一部分资金到这个通道中,初始情况下双方的分配方案就是预先存放的金额。在每一次发生交易时,双方都需要对交易后产生的分配结果进行确认,同时把原有的分配方案作废。这个过程涉及到的概念较多,而且比较巧妙,具体可参阅 A Dive into Lightning Network (Part One)[18],而它的作用是在闪电网络中的作用是构建双方之间的支付通道。

HTLC 是一种带事件的哈希锁定,它要求某一方在一定时间内提交某个哈希值 $h=H(m)$ 的原像 $m$ 以取得使用某一笔 UTxO 使用权。它在闪电网络中被用于构建支付路由,具体的实现过程见 Lightning network in depth, part 2: HTLC and payment routing[19]

闪电网络整合了这两种机制,使得交易可以在闪电网络中的任意两个节点间能够在链下完成。

Taro

主根资产(Taproot Assets,后续简称为 Taro)[20][21][22]是一种还在提议阶段的协议,它可以实现在 Bitcoin 上发行资产,这样的资产可以通过链上的交易通过比特币网络转移(对 NFT 的交易、转移已经被 Ordinals 实现)。特别地,同质化的 Taro 资产可以在存入闪电通道后在闪电网络上以更低的手续费、更为隐私地转移,类似的还有尝试在闪电网络上运行智能合约的 RGB 协议[23]

Taro 可以在 Bitcoin 主网或二层的闪电网络上流通。先考虑在 Bitcoin 网络的情况,Taro 是附加在交易上的哈希化元数据形式,使用哈希化的目的在于降低交易的占用空间以节省手续费。而这样的哈希化元数据形式则是 Taro 的核心,这样的一条哈希值甚至可以代表实际上的几百万次交易,它的原理会在后续进行介绍。

其次是 Taro 在闪电网络上的情况,使用闪电网络可以让同质化的 Taro 资产实现更快的交易速度,这类似于使用闪电网络可以更快、成本更低地转移比特币。在 Taro 的提议中,闪电网络自身不需要改变,为了实现一笔某种 Taro 资产的交易,只需要整条支付路径的第一条通道和最后一条通道可以识别 Taro 资产即可,而中途的路由通道则是正常的闪电网络转账方法,它们转账等价的比特币,这也导致 Taro 资产通常会在网络的边缘和其他资产交换。下图是 RIVER FINANCIAL 所展示的在闪电网络中实现 Taro 资产转移的过程。

Taro assets exchanged on the Lightning Network

资产树

资产树是 Taro 中的一种两级默克尔树结构,它被用来代表 Taro 资产。第一级是由 Taro 信息作为叶子节点而构成的默克尔树,而第二级则是通过 MS-SMT 构成的表示每个账户所具有的该资产的树,MS-SMT 的思想较为简单,它在默克尔哈希树基于哈希来构成树形结构的同时,每个节点还存放了左右两个子节点的和来实现(进行哈希运算本身也算一种求和),这样的资产树和 MS-SMT 树被用来构建 Taro 的 UTxO。

image-20230910203608411

资产叶(Aseet Leaft)是资产树中的最底层结构,它表现为资产树示意图中的淡蓝色节点,它以 assetScriptKey (assetScriptKey 可以类比 P2SH 交易中对交易脚本的哈希值)作为键。每个资产叶表示 Taro 资产的一个 UTxO,资产叶中包含的可选项可参见 Understanding Taproot Assets Protocol

Taro 资产发行

Taro 资产的发行需要一个标识符,正如 ERC-20 代币的智能合约会拥有一个地址一样,Taro 协议定义了标识符的生成方式:
$$
ID=SHA256(genesisPoint||assetTag||assetMeta)
$$
它将铸造资产所使用的交易输出信息、资产标签(例如资产名称的哈希值)以及资产的元数据(图片、链接或文档)进行哈希,从而得到一个标识符。

Taro 资产的转移脚本可以有类似比特币交易的输入输出,而创建资产的交易不需要包含任何的 Taro 资产的输入,由此可见,Taro 资产沿用了比特币的 UTxO 模型,资产的发行就是发布一笔 Taro 资产的交易,它没有输入,只有输出。

Taro 的输入和输出是基于资产树来实现的,正如前文所述,资产树的第一级代表了该笔 UTxO* (后面会继续沿用这种写法,表明这样的结构是在 Taro 资产中而非 Bitcoin中)中存放的 Taro 资产有哪些,而 Taro 资产 ID 所对应的 MS-SMT 中所存放的是该笔 UTxO\ 输出的 Trao 资产的信息。

构建一笔 Taro 资产的发行交易如下图所示,以一笔 Bitcoin 的 UTxO 作为输入,输出一笔正常的 Bitcoin UTxO 以及附加的 Taro 资产 A 的 UTxO*。这样的 UTxO*在 Bitcoin 上表现为一个默克尔根的形式,而它在链下表现为资产树的形式,资产树中记录了 Taro 资产 A 的 assetId 以及资产 A 对应的 MS-SMT 中的记录。

image-20230910203812171