作者:jurvis
来源:https://delvingbitcoin.org/t/chain-code-delegation-private-access-control-for-bitcoin-keys/1837
在过去几个月中,@jesseposner 和我一直在探索一种联合保管(collaborative custody)的新方法,叫做 “链码委托(Chain Code Delegation)”。通过扣住 BIP-32 密钥派生中的链码(chain code)、仅在签名时刻才分享标量调整项(scalar tweak),这种技术让托管人可以强制执行特定的花费策略(比如花费速率控制),又无需拥有一个 XPUB (XPUB 会让他们可以完全看到一个密钥的完整密钥树)。以下,我们会勾勒这种设计背后的核心概念。
(译者注:联合保管指的是在自主保管装置中加入保管人,使之可用于复原钱包 —— 但是不将资金完全交给保管人 —— 的保管模式。)
引言
在使用 Script 发送一笔交易时,多签名的赎回脚本包含了所有参与其中的公钥。因此,联合保管服务的主导公钥(predominant key)安排,给了托管人持续地视察其对手方(也即用户)的交易历史的能力。举个例子,在一个使用公钥 A、公钥 B、和公钥 C 的 2-of-3 的多签名脚本中,如果一笔交易得到了 A 和 B 的签名,但是,即使交易并不包含 C 的签名,赎回脚本中也包含了 C 。因此,联合托管人可以监控区块链、寻找任何包含了 TA 的公钥的交易,以识别由 TA 的对手方花费的交易,不论他们是否被对手方要求参与签名。
对这个问题,一种解决方案是放弃使用 Script,转而使用多方计算(multiparty computation,MPC),比如 FROST(最优轮次的灵活 Shcnorr 阈值签名),如 Nick Farrow 所建议的【0】。另一种解决方案,则是使用 Tapscript 的非交集花费路径。比如说,一个 2-of-3 多签名可以表达成一个 Tapscript ,它有 3 个分支、由参与的 3 个公钥两两形成 2-of-2 多签名组合而成。使用其中一个分支来花费,不会揭晓放置在其它分支中的公钥。但是,上述方法都不适用于 ECDSA 签名(译者注:意思是比 P2TR 更古老的输出类型)。
另一种既不要求 Tapscript 、也不使用 MPC 的方法是,去除联合保管人的链码、仅仅给托管人提供签名所需的 BIP-32 标量调整项。在 BIP-32 层级式钱包中,一个拓展密钥是由一个标准的密钥加上一个 32 字节长的 “链码” 组合而成的;两者结合在一起,就能派生出一棵完整的密钥树。扣住链码之后,托管人就只持有一个非拓展的密钥对。当一笔交易需要签名的时候,对手方就计算所需的标量调整项,然后仅仅分享这个调整项给托管商。因为缺失了链码,托管商就无法计算自己不签名的赎回脚本中归属于自己的公钥的子公钥、也无法监控这些子公钥 —— 所以他们只能了解到对手方显式给予的交易。
除了隐私性好处,链码委托还限制了安全性爆炸半径:没有链码(或者说未揭晓的调整项),托管商在任何自己还未签名过的 UTXO 中,都是实质上无法花费的。调整项仅会在一笔交易要花费(与这个 调整项/公钥)相关的 UTXO 时才会揭晓给托管人,也就是说,按照常理,这些输出马上就要被花费掉了。即使托管人的系统被爆破、泄露了一个调整项,攻击者也仅有一个非常短的时间窗口来跟用户赛跑。而一旦用户的交易得到确认,这个调整项也就过时了,因为它对未来的签名完全无用。
这种技术可以推广到其它需要强制执行访问控制策略 —— 密钥的信息访问和可签名 UTXO 范围 —— 的装置中。
设置
在常见的联合保管装置中,联合保管人从一个 BIP-32 种子种派生出一个子密钥,然后将这个拓展公钥(xpub)发送给对手方。然后,对手方使用这个 xpub 来派生多个多签名脚本,每个脚本都使用来自这个 xpub 的不同子公钥(即生成多个地址)。
然而,在链码委托装置种,联合保管人只生成一个标准的(即非拓展的)密钥对,然后将公钥提供给对手方。托管人不生成链码,相反,对手方代替联合托管人生成一个链码,但并不揭晓给托管人。结合这个链码和托管人的公钥,对手方就能为托管人构造出一个 xpub(然后生成多签名脚本)。
签名
在对手方请求联合托管人签名一笔交易时,TA 从这个托管人 xpub 派生出 BIP32 标量调整项(即来自 BIP32 的 parse_256(I_L) 的值),然后提供给托管人。
# 输入:
# 链码 :32 字节长的链码(对托管人隐藏)
# P_par :托管人公钥(压缩的)(此处用作父公钥)
# i :用于花费的子公钥索引号
I = HMAC-SHA512(key = chain_code,
data = serP(P_par) || ser32(i))
I_L = I[0:32] # 左半边
t_i = parse256(I_L) # 标量调整项模 n
然后,为了用这个子密钥签名,托管人通过给自己的公钥加入这个调整项来计算子公钥、给自己的私钥加入这个调整项来计算子私钥:
# 对手方 → 托管人:发送 t_i
# 椭圆曲线语境:
# G = 椭圆曲线生成元
# point_add = 椭圆曲线点加法
# scalar_mul = 椭圆曲线标量乘法
# n = 椭圆曲线阶数
# 2a. 子公钥
P_i = point_add(P_par, scalar_mul(G, t_i))
# 2b. 子私钥
k_i = (k_par + t_i) mod n
有了子私钥 k_i ,托管人就可以对这笔交易的sighash 产生一个标准的签名(例如,Schnorr 签名或者 ECDSA 签名):
# 计算要签名的摘要
msg_hash = compute_sighash(unsigned_tx, utxo_set, sighash_flag)
# 生成签名:
sig = sign(k_i, msg_hash)
通过分离调整项派生(链外)和密钥使用(设备内),链码委托技术让托管人仅仅能在需要他们的时候签名 —— 永远不能获得派生以及观察任何其它子密钥和交易的能力。
找零输出验证
为了强制执行花费限制策略,联合托管人必须验证找零输出被发回给了对手方。通常来说,办法在创建钱包期间给托管人一个描述符、从而托管人可以推导找零地址并在签名交易时验证。但是,在链码委托中,托管人不能知道任何链码,因此也无法访问 xpub 和描述符。
因此,在签名时,对手方需要提供一个标量调整项列表 $t_i$ ,每个签名公钥在索引号 i 上都要有一个调整项。
对于每一个找零输出,对手方计算:
# 输入:
# 链码 :32 字节长的链码(对托管人隐藏)
# P_par :父公钥(压缩的)
# i :子公钥索引(例如,找零输出索引)
# 1. 计算 HMAC-SHA512 伪随机数据
I = HMAC-SHA512(key = chain_code,
data = serP(P_par) ‖ ser32(i))
I_L = I[0:32] # 左边的 32 字节
# 2. 解析标量调整项
t_i = parse256(I_L) # 整数模 n
然后,收到了调整项 t_i 和父公钥 P_par 之后,托管商就计算:
P_i = point_add(P_par, scalar_mul(G, t_i))
这将产生会出现在找零输出中的确切子公钥 P_i 。
然后,就可以构造出与预期中的脚本公钥:
change_script_i = OP_0 || SHA256( sorted_multi(P_1, P_2, P_3, …) )
然后就可以验证这个脚本公钥与 TA 在待签名交易中见到的相同。
这个办法行得通,是因为,在建立钱包期间,托管人也被给予了找零公钥的非拓展父公钥,从而 TA 可以验证找零输出:使用这些父公钥、索引这些即将用于找零输出的找零子宫要的标量调整项。
隐私性
没有链码,托管商只知道自己已经签名的交易。对于隐私敏感交易,对手方可以有意自己签名、不召唤托管人,而托管费将无法仅仅凭借所有自己的密钥材料来探测出这些交易。
若要获得完整的隐私性,也就是让托管人甚至无法了解自己签名的交易,链码委托可以结合盲化的 Schnorr 签名。使用这种技术,对手方可以在收到的托管人签名上应用 BIP32 调整。因为 Schnorr 签名的线性性,这是可以做到的:
$$s = r + c * x $$
$$s + c * t_i = r + c(x + t_i)$$
对于需要强制执行花费策略的托管商,“谓词盲签名”【1】可以跟盲化 Schnorr 签名结合使用,从而零知识证据可以断言关于被签名交易的任意谓词。
安全性
没有链码或者标量调整项,托管人密钥是无法用来签名任何 UTXO 的。这显著压缩了托管人密钥遭到劫持的爆炸范围。
在托管人了解导一些标量调整项的时候,TA 正在签名将要花费跟这些标量调整项相关的 UTXO 的交易,这就迅速限制了由这些调整项派生的子密钥的有用性。如果一个托管人的系统完全被攻破了,攻击者充其量只能跟对手方赛跑、签名标量调整项已经泄露的 UTXO 。当然,除了托管人密钥,攻击者也必须获得足够多的用户密钥,以满足多签名脚本的签名要求。
这种机制在限制其它语境下的密钥暴露的爆炸范围时,也是十分有用的。比如,如果一个比特币用户持有一个签名密钥、存放在自己的手机里;该用户可能希望限制这个密钥的权限,因为手机这个执行环境接触更大的攻击界面。一个专门的设备,比如一个硬件签名器,可以用来为这个手机密钥生成一个链码,然后向手机选择性地暴露标量调整项。这个手机将只能用来花费自己收到了调整项的 UTXO,所以这个用户可以随时确定这个手机能够访问的 UTXO ,既包括过去的,也包括未来的 UTXO 。
参考文献
- [0] 使用 FROST 的隐私联合保管:Private Collaborative Custody with FROST · GitHub
- [1] 并发安全的盲化 Schnorr 签名:Concurrently Secure Blind Schnorr Signatures
(完)