Taproot简介

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,软分叉来实现。
  • 花费路径有两个,二选一:
    1. 签名模式:N+1参与方全部签名
      • 可以聚合出组公钥P的签名。验证签名后即可花费,无需暴露脚本
    2. 脚本模式:N个参与方里,任意一个或以上拒绝签名。则走脚本模式:
      • 提供:组公钥C、脚本S、以及脚本S相应的数据,即可以花费

示例说明

为了搞清楚运作过程,我们举例说明一下。

  • 两个参与方,分别持有公钥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
2
3
4
P = C + H(C||S)G
= C + D
= A + B + D
= aG + bG + dG

本例其实是三个私钥在参与,只是第三个私钥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
2
3
4
5
6
7
8
9
10
11
1. 计算出私钥d: d = H(C||S)

2. 计算出d的公钥: D = dG

3. 验证公钥: P == C + D

4. 构建出完整脚本:DATA || S

5. 执行脚本,并判断结果是否为True

// 上述过程都顺利通过的,则可以花费。

通常,脚本通常都是带延迟条件的,具备一定惩罚性质,例如N天后可以花费,或者多少高度后才可以进块等。当然,也可以不设置延迟条件,脚本内容是没有任何限定的。

总结

Taproot只有在非合作时下才会暴露并执行脚本,签名模式下看上去就是一个再普通不过的公钥签名交易而已。

  • 在Taproot里,是N方参与,N通常>=2。(N=1技术上可行,但没有太大意义)
    • N方参与,则必须有N方签名,签名数量小于N则无法验证通过。缺任意签名则合作模式失败。
  • 两个分支其实已经可以覆盖很多场景,甚至大部分场景。
  • 一般来说,N方大概率都是合作的。

Taproot一个典型应用场景就是闪电网络的交易。当然,Taproot是灵活的,更多应用场景等待挖掘。


参考: