MimbleWimble技术随笔
上交所技术公司 朱立
主打构建隐私保护数字货币的MimbleWimble协议,相关的中文帖子讲故事的多,纯技术的少。笔者所见最清晰的中文干货文章可能要数Grin团队的这篇文章(重复其中内容另写一篇很可能已经意义不大),虽然不可否认英文版的内容会更精确。伏地魔最早贴出的设想和Andrew Poelstra的改进版(改动了交易构建流程,提出了一个summable sinking signature,并在区分proven work和expected work的基础上给了一个新的POW算法)当然也应该读,但不得不说后者的文字实在太晦涩了,尤其是如何构建交易部分写得几乎可以用“不知所云”来形容。Georg等人写的这篇论文清晰解释了MimbleWimble并完成了相关安全证明,同时也指出了伏地魔原始建议书中和交易构建方式相关的一个安全问题——币的发送方可以稍后构造一个逆交易把币从接收方处又转回来。要了解Grin和BEAM团队为何采用了现有的交易构建方式,此文不可不读。Nervos团队录播的这档节目也值得收听。
关于如何协作构建一个交易,中文文章似乎目前未见。Grin团队给出了一幅图(见上面,上传到简书后似乎变得不太清晰,原始链接在这里),已经将这部分内容表达得很清楚,也不需要多余的解释。
为了行文方便,先简单解释一下本文不太正式的用语:如果G是一个群的生成元,x是一个整数,对于等于(x*G)的表达式本文简称为“群元素”,对于x这种整数加减乘形成的结果本文简称为“系数”。
协作构建交易的流程,其技术本质是双方协作针对Excess及其他信息生成以Excess为公钥的Schnorr签名(wiki上的介绍在这里), 但略作了调整以便任何一方都不掌握公钥对应的私钥。Grin团队用的Schnorr签名方案和BEAM团队在这篇文档中提及的方案接近,最终生成的签名都由两个分量构成,其一是群元素(如椭圆曲线上的点,之所以采用原始Schnorr签名相应分量对应的公钥元素应该是出于信息保密原因), 其二是系数,这一点对于签名防伪非常重要,背后的理由当然还是离散对数难题。
根据笔者的理解,之所以要将Excess作为某种公钥,同时要能够生成一个签名用来证明其私钥至少是由资金的发送方和接收方“共同”拥有(但任何一方都不知道实际私钥),是因为这里Pedersen Commitment(vH + rG)中的G和H是同一群的不同生成元,如果不能证明交易参与方(至少以某种方式“共同”)拥有G的系数(私钥),那Excess部分本也是个群元素,自然可以表达为用某个未知系数x再乘以G,单纯这样就可能存在发送方回头把刚才给到接收方的币再偷回来的事情,因为这种情况下发送方是知道那些币的v分量的总和的。现在由于需要证明拥有Excess这个公钥的私钥的某种知识,如果没有币的当前拥有者的配合,基于离散对数难题的保护,试图盗币者是没有办法简单猜出适当的私钥的。附带提一句,在伏地魔的最初论文中,Excess的私钥接收方是知道的,且只有接收方知道,然而这一点其实并不必要。
关于如何构建一个交易,BEAM团队有一篇有意思的文档,看上去和前述做法很类似,但仔细阅读就可以发现存在不同:这里Schnorr签名只有一个以群元素形式出现的分量——这当然有些怪,何况这篇文档还没说应该如何验证签名,所以只能猜想作者的本意是要补上另一个群元素形式的nonce分量(这个分量哪怕用系数给出也没法就证明拥有对应私钥的),然后验证者可以少做一步乘以G的操作(?)。脑补之后,其最终签名会类似这种样子:(K, -K-Hash(K|M)*X),其中K是以双方合作产生的nonce为系数的群元素,M是被签名消息,X是Excess。如果仅从Schnorr签名的角度看,这种签名是容易伪造的,任何人如果随机生成K,代入后不是很容易构建一个能够满足验签要求的X出来吗?这样一来不是有悖于要求以某种方式了解相关私钥背后的动机?诚然,单从这方面推演,这个签名方案是不完善的。但是攻击者现在面临的问题是要以给定的X为公钥生成符合要求的签名,因此他的问题是必须利用给定的X和M推求合适的K,而不是从K求X,所以最终协议仍然是安全的(感谢万涔涔同学指出了这个“但是”)。从源码看,BEAM并未按照这篇文档的做法在开发,反而类似于Grin的做法,最终签名采用的是[P, x]的形式,其中P是群元素,x是系数。
如果使用BLS签名而非Schnorr签名,似乎可以在共同产生签名的同时还能让这些签名进一步合并起来,从而令整个BLOCK只剩下一个Excess和一个签名,但不知道为何两个团队都没有采用这种方式,可能别有玄机吧。一个说得过去的解释是两个团队都希望能针对一些变化的内容如fee或者height等一并签名,这种情况下把不同交易的签名再度合并的机会就消失了。
单靠MimbleWimble协议还不能很好地保护隐私。UTXO的聚合操作是矿工做的,UTXO之间的关联关系对于矿工当然是可见的。不管最终成功出块者是谁,刻意监听者只需建立一个全节点持续侦听记录待打包交易就可以了解到UTXO之间的关联关系,完全不受之后出块者聚合操作的干扰。因此,还需要依靠Dandelion系列协议的卡位来弥补这一不足。其核心思想很简单,就是交易发送到网络上后,开始只随机中继地沿着一个“茎”进行小范围传播,过程中顺便进行聚合操作,经过若干跳后再转变为传统的gossip传播,比拟为蒲公英的种子被吹散到各处。
如果单个块中的交易关联很小,那么实际发生的cut-through也会很少。不同块之间的交易进一步cut-through只是节约好节点存储空间的办法,本身不能阻止这部分信息被有心的节点关注并记录。
似乎有人表示过对MimbleWimble在发生cut-through后能否防止双花表示疑问,因为第一反应是交易历史被删除了所以没法防止双花。被cut-through删除的UTXO一定是被花掉的UTXO,所以我们可以这样看:试图花一个暂时还存在某处但已被花掉的UTXO(逻辑删除),和试图花一个已经被物理删除的UTXO,这二者其实没什么不同,所以只要各节点见到且认定的交易历史确实是各节点一致的,cut-through只是把逻辑删除变为物理删除的空间优化方案,但不存在双花的问题。
不支持脚本语言确实是这个协议的天然短板,但也不是啥有趣的事情都做不了,比如时间锁、原子互换、闪电网络等都是可以支持的(点击阅读这里和这里)。