Taproot的概念由Gregory Maxwell在2018年01月提出,Taproot: Privacy preserving switchable scripting,这个概念主要是他研究一番MAST后,发现可以与Schnorr签名一起构成一个特别简洁的输出模式。
定义
Taproot定义了一个输出,两个执行路径的实现方式。
- N个参与方,构成组公钥C:
C = A + B + … + N - N + 1个参与方,构成输出组公钥P:
P = C + H(C||S)G- 多出的一个参与方是:
H(C||S),组公钥C和脚本S的组合哈希。
- 多出的一个参与方是:
- 交易输出中填入组公钥P,格式类似Segwit:
[ver] [P]- ver=0,segwit已经使用了。Taproot可用ver=1,软分叉来实现。
- 花费路径有两个,二选一:
- 签名模式:N+1参与方全部签名
- 可以聚合出组公钥P的签名。验证签名后即可花费,无需暴露脚本
- 脚本模式:N个参与方里,任意一个或以上拒绝签名。则走脚本模式:
- 提供:组公钥C、脚本S、以及脚本S相应的数据,即可以花费
- 签名模式:N+1参与方全部签名
示例说明
为了搞清楚运作过程,我们举例说明一下。
两个参与方,分别持有公钥A、B。那么其组公钥(聚合公钥)就是:
C = A + B。定义脚本S:
<timeout> OP_CSV OP_DROP B OP_CHECKSIGVERIFY,这个脚本的含义是“N天过后,B一个人签名就可以花掉这个输出”。
那么把上面几个东西拧一起,定义一个新的公钥:P = C + H(C||S)G。
放到输出里,[version] [P]:
- version,版本号,用于表示taproot的版本
- P:公钥
令:d = H(C||S),则有H(C||S)G = dG = D 。那么:
1 | P = C + H(C||S)G |
本例其实是三个私钥在参与,只是第三个私钥d是双方共同持有的,外界仅知道组公钥P。
Taproot的签名算法采用Schnorr Signature,然后定义两个花掉此输出的方式。
方式一、签名模式花费
合作模式利用了Schnorr签名的线性特性,若P = A + B + D,则公钥A、B、D的单独签名叠加起来就是公钥P的签名。
A、B都签名(D必然签名,因为私钥d是双方共享的,任何一方都可完成D签名),那么把A、B、D三个签名加起来就是P的签名。
双方合作的话,外界看上去就是一个正常的P的签名一样,这个交易也与普通的转账完全一样。其脚本信息则完全隐蔽掉了。
当然,参与方不限定两个,可以是N个。
方式二、脚本模式花费
若A或者B任何一方拒绝签名,则无法产生(叠加出)公钥P的签名(此时仅有A+D的签名,或者B+D的签名),也就无法花费此输出。
假设A拒绝提供签名,那么B就无法合成出P的签名,但B可选择执行脚本进行花费。B需要提供的有:
- 公钥C
- 脚本S
- 符合脚本S的执行数据DATA(本例是B的签名)
其他节点收到这样一笔交易后,验证过程:
1 | 1. 计算出私钥d: d = H(C||S) |
通常,脚本通常都是带延迟条件的,具备一定惩罚性质,例如N天后可以花费,或者多少高度后才可以进块等。当然,也可以不设置延迟条件,脚本内容是没有任何限定的。
总结
Taproot只有在非合作时下才会暴露并执行脚本,签名模式下看上去就是一个再普通不过的公钥签名交易而已。
- 在Taproot里,是N方参与,N通常>=2。(N=1技术上可行,但没有太大意义)
- N方参与,则必须有N方签名,签名数量小于N则无法验证通过。缺任意签名则合作模式失败。
- 两个分支其实已经可以覆盖很多场景,甚至大部分场景。
- 一般来说,N方大概率都是合作的。
Taproot一个典型应用场景就是闪电网络的交易。当然,Taproot是灵活的,更多应用场景等待挖掘。
参考:
- [bitcoin-dev] Taproot: Privacy preserving switchable scripting