比特币源码阅读(0.16)(二十二)

Pay-to-Script-Hash

BIP-16改进方案在2012年引入了首字符是“3”的P2SH(Pay-to-Script-Hash)地址。P2SH的灵活性来自于它巧妙的设计——交易的输出并不像P2PKH那样直接保存上锁脚本,而是记录20字节的脚本哈希,形式是这样的:

1
HASH160 PUSHDATA(目标脚本哈希) EQUAL

光根据脚本哈希,外人无从推断出解锁的逻辑。等我们转账时才需要出示与该哈希对应的原始脚本,并且保证脚本的运行结果为真。

P2SH最常用于M-of-N多重签名,也就是在预定的N个公钥中,给出M个相应的签名就能通过验证(1 ≤ M ≤ N)。我们来看个2-of-3 multisig的具体例子。

先生成三组私钥和压缩形式的公钥。这个过程通常由三个人私下完成,各自保管自己的私钥:

私钥A:
L2iQ55QcE6otmfUZPLYU2Qf5SP41HhCtPEKu2v3r16vHZ19MT7Sn
公钥A:
020FA7BED1B89DF218A2ED2C94EBBF872A7BDA0F48D231EB8CB6F16B87D9BB5211

私钥B:
L37gNgdvmLJuLNre3EASs2ETkEvrUn8AShviJTD2TfNaqWiEgwRT
公钥B:
02D7E287092457F2BEA226CD7537C5EE99AF50CCA923795A2EA65CF249F783C5D1

私钥C:
Kwd8QPXS1LZAGmqJDvb5emRtEPJuVjzXX2FRUZrYERMTt5uz58Vr
公钥C:
02E8B48F3C0A7C452792FA96CDCF2FC6A23298F4D6512BD8AA9A25210B66A1D450

用这三个公钥就能组合成2-of-3上锁脚本:

2 PUSHDATA(公钥A) PUSHDATA(公钥B) PUSHDATA(公钥C) 3 CHECKMULTISIG
其中的2和3分别表示向堆栈压入数字2和3的操作。CHECKMULTISIG用于检查堆栈上的两个签名是否对应三个公钥中的两个。

以上脚本编译后的结果共计105字节,十六进制表示如下:

5221020fa7bed1b89df218a2ed2c94ebbf872a7bda0f48d231eb8cb6f16b87d9
bb52112102d7e287092457f2bea226cd7537c5ee99af50cca923795a2ea65cf2
49f783c5d12102e8b48f3c0a7c452792fa96cdcf2fc6a23298f4d6512bd8aa9a
25210b66a1d45053ae

对它先求SHA256,得到32字节的哈希:

6feec0468378f4a1f0c8dbccfd41f6041eaf0185d22d029d2dea4603ed8c94bf

再对以上结果做RIPEMD160,得到20字节的哈希:

c19ba54b40598eab41f636b4b5c3fe6493dddd64

这就是P2SH上锁脚本中PUSHDATA里的目标脚本哈希。加上固定前缀0x05后作Base58Check编码便得到了最终的、首字符是“3”的P2SH地址:

3KLio22Epg8nrXfzFBuoHWwxFPCkpFzYFo

转账时需要提供两个签名和原始脚本,解锁形式如下:

1
0 PUSHDATA(签名D) PUSHDATA(签名E) PUSHDATA(脚本)