部分签名交易
部分签名交易(Partially Signed Bitcoin Transaction, PSBT)是在 (BIP-174)[https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki] 中提出的一种交易格式,它使得用户可以对交易中的一部分输入进行签名,最后和其他用户的输入一起组成新的交易。这种交易格式的应用在于:
- 离线钱包签名:观察签名进行交易的构造,随后由冷钱包完成签名,最后再广播到节点上,从而保证冷钱包的安全性;
- 多方交易:多个签名者之间传输交易,最后组成新的交易;
- NFT 市场:现有的铭文协议中,通常使用 PSBT 来构建买卖双方的交易,由 Dex 完成组装后完成双方的交易;
PSBT 规范
PSBT 的格式由一系列的键值对映射组成,键值对由 0x00 作为终止符,其二进制下的å格式如下[1]:
1 | <psbt> := <magic> <global-map> <input-map>* <output-map>* |
依次对应每个值,有:
1 | <magic> := 0x70 0x73 0x62 0x74 0xFF // "PSBT" 的 ASCII + 0xFF 结尾 |
而键值对的组成如下:
1 | <keypair> := <key> <value> // key-value |
全局键值对、输入键值对、输出键值对定义了多种键类型(keytype),具体可参考 BIP-174 - Bitcoin Wiki
在所有签名者完成签名后,需要将所有的 PSBT 组合为一个 PSBT,完成该功能的角色被称为 Combiner,它最终会输出一个 PSBT,交由 Input Finalizer 进行处理
签名与签名类型
签名
在 Bitcoin 中,签名是 DER 格式的 ECDSA 签名,其签名以 0x30 标识符开头,在 DER 中表明这是一个组合的结构,然后跟一个表示结构长度的字节。这个组合结构就是 ECDSA 签名下的签名输出 $\sigma=(r,s)$
具体地,它的编码格式如下图所示[2],签名的格式实际上是对签名最终输出的 $(r,s)$ 进行二进制序列化
签名的过程根据 Pay-To 方式的不同划分为两种,分别用于非 Sigwit 交易和 Sigwit 交易,详见 Signature - Learn me a bitcoin 的 Legacy Algorithm 和 Segwit Algorithm 两种算法。Segwit 算法在 BIP-143 中被提出,它将交易数据划分为单独可重用的各个部分,便于加快交易的验证流程。
在 DER 签名的最后还有除签名本身之外的长为一个字节的 SIGHASH 字段,它用于标识签名的类型。
签名类型
以下内容需要分别对 Legacy 和 Segwit 签名算法中的“交易数据哈希 - Step.4”和“原像构造 - Step.1”过程有一定的了解才便于理解
在构造 Bitcoin 交易的过程中,签名必然需要针对某一交易进行签名,可以使用 $\sigma \leftarrow Sign(pk, m)$ 来表示这一过程,对交易数据进行哈希和构造原像就是为了得到这里的 $m$
构造哈希和原像的过程会得到一个待签名的消息 $m$,签名类型用于指定这个消息 $m$ 所关联的输入和输出,签名类型在签名完成后追加在 DER 格式的签名的最后作为签名的一部分。在 bitcoin 的代码库(bitcoin/src/script/interpreter.h)中定义了签名类型:
1 | enum |
前三种 SIGHASH_ALL
、SIGHASH_NONE
和SIGHASH_SINGLE
指定关联了交易中的所有输入,分别指定不同的输出
上图展示了前三种签名类型所关联的输入、输出,这三种签名类型都会和所有的输入关联,不同在于关联的输出。左侧和右侧分别代表了交易的输入和输出,红色的是当前待签名的输入,黄线则是签名所关联的输入或输出
SIGHASH_ALL
:关联所有的输入和输出,这是面向消费者钱包的默认签名类型;SIGHASH_NONE
:仅关联所有的输入,但是和任何的输出都没有关系;SIGHASH_SINGLE
:关联所有的输入,同时关联一个和当前输入所在位置一样的输出,例如图中红色表示待签名的输入,那么关联的输出是对应位置上的输出;
SIGHASH_ANYONECANPAY
和前面的三种签名类型一起使用(在位运算中通过按位或的方式来连接),但是它只用于指定当前签名的输入,这是部分签名实现所需要的基础
SIGHASH_ALL|SIGHASH_ANYONECANPAY
:关联该输入的同时关联所有的输出,即在同意输出的情况下加入一笔交易;SIGHASH_NONE|SIGHASH_ANYONECANPAY
:仅关联当前的交易输入,是一种极不安全的签名类型。这代表输入可以被纳入到任何的交易,即允许这笔输入的比特币被任何人使用,可以被用作燃烧证明;SIGHASH_SINGLE|SIGHASH_ANYONECANPAY
:关联输入本身和对应位置上的输出,这是一种常用的部分签名交易。现在常被用于比特币上的交换协议中。例如在 Ordinals 协议下,输入中携带了一个 NFT 资产,那么需要交易的情况下可以指定该输入,并指定一个输出,要求在这个输出下向自己的地址发送一定数量的 btc。这样的部分签名就可以用于实现交易市场,这也是目前的大部分交易市场实现的原理;