P2TR
: Pay To Taproot, 意为支付到 Taproot
。由于是隔离见证的第 1 个版本, 所以也叫 V1_P2TR
。
锁定脚本
P2TR
锁定脚本的操作码模板:
以下是一个 P2TR
锁定脚本的示例:
OP_13cb650a3809269365cfea9874982c00b2f61951203a6f3b3686848f1e1b08d46
OP_1
是隔离见证的版本字节, 表示该锁定脚本是 P2TR
。
Taproot 输出公钥 是一个 32
字节的公钥, 由内部公钥和脚本树的默克尔根计算得到。
-
内部公钥是用户私钥经过 secp256k1
曲线生成, 实际上就是用户公钥。但在计算 Taproot
输出公钥时, 只会使用公钥的 x
坐标。
-
Taproot
允许多个锁定脚本, 任意一个锁定脚本的解锁即可花费 UTXO
。 在有多种锁定脚本的情况下, 将多个锁定脚本通过 MAST
构造成一个脚本树, 脚本树的默克尔根参与计算 Taproot
输出公钥。在花费时, 可以选择其中一个锁定脚本并提供解锁脚本, 同时还需要提供默克尔证明。假设使用上图中 Script_A
来花费 UTXO
, 除了解锁脚本外, 还需要其默克尔证明 B
和 C
。
多种锁定脚本可以是完全自定义的脚本, 也可以是标准脚本, 例如:
锁定脚本经过 taggedHash
运算后, 成为脚本树的子节点。将所有子节点构造成一个默克尔树, 得到默克尔根。内部公钥和默克尔根拼接后经过 taggedHash
运算计算出 tweak
值, 简称 t
。
t=TaggedHash(′TapTweak′,P+Root)
内部公钥加上 t
乘以椭圆曲线 secp256k1
的基点 G
即可得到 Taproot
输出公钥 Q
。
Q=P+t×G
Q
是椭圆曲线的一个点, 但在实际中, 只会用到其 x
坐标, 因此 Q
实际指的是点 Q
的 x
坐标。
将 Q
进行 bech32m
编码即可得到 Taproot
地址。 当向 Taproot
地址转账时, 对其执行 bech32m
解码可得到地址的 Taproot
输出公钥, Taproot
输出公钥最终会被存入 UTXO
锁定脚本中。
脚本树可以为空。 在比特币钱包中, 默认生成的 Taproot
地址都是在没有脚本树的情况下:
Taproot 地址生成器
从公钥生成 P2TR 地址
解锁脚本
要解锁 P2TR
, 有两种方式:
- 秘钥路径 -
Key Path
- 脚本路径 -
Script Path
秘钥路径
只有持有内部公钥对应的私钥才能使用秘钥路径解锁 P2TR
, 解锁脚本只有一个签名数据。
以下是一个秘钥路径解锁 P2TR
的交易示例:
02000000000101c1d468b687c165337bcf3ca07194b142f09d4f74e244044a6a8fee9d5539f0ab0200000000ffffffff025798000000000000160014f90371a81f05e7f13091c523ac4ab2f438f9e30272003000000000002251203cb650a3809269365cfea9874982c00b2f61951203a6f3b3686848f1e1b08d460140ad06bd890367e518991fa7337b834032d824586b61d95cf84c0a53ee2c58cb37b53e324c8f85609da8f90da48f35af10121420f112dfc91ea6ed5fccfa0c5f8a00000000
该交易只有一个输入, 对应的 Witness
字段为
包含的元素只有一个, 即 Schnorr
签名数据。
需要注意的是, 秘钥路径花费时, 不需要执行脚本。只需要验证签名和锁定脚本中的 Taproot
公钥是否匹配即可证明交易的有效性。
脚本路径
另一种花费方式是通过脚本路径。假设脚本树中有三个锁定脚本
可选择的花费方式有:
- 拥有内部私钥可直接选择秘钥路径花费
- 没有内部私钥时, 只能选择脚本路径花费方式, 从脚本树中选择任意一个可满足条件的锁定脚本
- 选择
ScriptA
, 需提供默克尔证明 B
和 C
- 选择
ScriptB
, 需提供默克尔证明 A
和 C
- 选择
ScriptC
, 需提供默克尔证明 AB
解锁 P2TR
的 Witness
字段格式为:
假设现在选择 ScriptA
花费, 需要使用 Alice
的私钥签名交易得到签名数据, 以及 ScriptA
本身和控制块, 最后将这三个元素组合成 Witness
字段:
<Alice签名> <ScriptA> <控制块>