技术干货 | 深入理解Zcash的零知识证明体系
前言
主要分享Zcash Sapling版本的协议细节。多多指教^_^!!!Zcash
迄今为止,Zcash总共经历了三个版本的迭代,第四次版本升级时间预计在12.11.2019,据官方介绍,此次更新主要是缩短了出块的时间,详细内容见 Zcash网络信息 。作为零知识证明的成功应用项目,让我们带着以下几个问题去研究Zcash的机制:
1. Zcash是如何隐藏发送方的? 2. Zcash是如何隐藏接收方的? 3. Zcash是如何隐藏交易金额的?
**建议:阅读本文前,您最好已经了解了: 1. note的概念; 2. 零知识证明的基本概念;
Sapling
本篇主要分享Zcash Sapling版本协议的主要细节,相对于Sprout版本,还是做了很多的修改和优化,在此不做详细的对比分析。回归到大方向,无论是Sapling版本,还是Sprout版本,交易的整体流程都可以简要概括为以下三个步骤: 1. 交易者发起交易; 2. 交易者生成zk-proof,和signature, 验证者验证; 3. 接收者接收交易;接下来,我们将尽量仔细挖掘每一个步骤,去探索一下,它是如何实现这三点的。
Transaction
在这里,我们不详细介绍交易发起者是如何发起一起交易的,我们直接介绍Sapling中的交易结构,如图所示:实际上,Sapling的交易结构内容不止这些,在这只是罗列出Sapling特有的一些字段及相应的解释,完整的交易结构在协议说明书的7.1章节有详细介绍。
在Sapling中,交易由Spend Transfer和Output Transfer组成,分别对应隐匿的输入和隐匿的输出,而spendDescription和output Description是用来分别描述Spend Transfer和Output Transfer的数据字段,它们被各自编码表示成vShieldSpend和vShieldOutput字段储存在交易结构中。接下来,重点介绍vShieldSpend、vShieldOutput、valueBlance、bindingSig四个字段表示的内容。
1. vShieldSpend
一个vShiledSpend对应着一个SpendDescription,一个可靠的SpendDescription表示一个note的有效花费,它包含的内容如下图所示:cv:对Inpunote 的value的承诺,所谓承诺,其实就是对v值的一种隐藏,这种隐藏是单向的,不可逆的,也不可伪造; anchor:cm默克尔树的根,用于验证inputnote的存在性及有效性; nullifier:note的唯一性标识,用来防止同一note被重复花费; rk:用于验证消费授权签名; zkproof:零知识证据,在不透露相应隐私的情况下,证明note的有效性、花费note的权力、隐私地址的有效性 spendAuthSig:用私钥对spendDescription签名,对note的花费进行授权
2. vShieldOutput
同理,一个vShiledOutput对应一个OutputDescription,一个可靠的OutputDescription表示产生的新note的有效性,它包含的内容如下图所示:cv:对outputnote 的 value的承诺,亦满足单向性,不可伪造性; cmu:对outputnote的承诺,承诺的数学形式是曲线上的一个点(u,v),cmu为点的u坐标; ephemeralKey:临时公钥,用于计算解密密钥 encCiphertext:noteplaint的密文,noteplaint是note的具体内容; outCiphertext:用来计算共享密钥的信息密文,可用来恢复noteplaint信息 zkproof:零知识证据,在不透露任何隐私的情况下,证明新生成Note的有效性
3. valueBlance
valueBalance表示此transparent value pool的变化量,由Spend Transfer的v总和减去Output Transferd的v的总和得出。当valueBalance 为正数时,表示从Sapling value pool转移valueBalance至transparent value pool,如果为负数,则执行相反的操作。 valueBalance将在bindingSig中,用于验证交易的balance 属性。4. bindingSig
在Sapling中,bingingSig发挥两个作用。第一,保证了交易的balance属性;第二,利用计算输入和输出note cv的随机数rcv,来生成签名私钥,防止outputDescription被攻击者进行重放攻击(spendDescription的防重放攻击由spendAuthSig来保证)Zk-proof and Signature
在Sapling中,交易者总共要生成两个zkproof(spend zkproof & output zkproof)和两个签名(spendAuthSig & bindingSig)。下面逐个介绍。1. spend zk-proof
spend zkproof 主要是实现了在不暴露任何隐私信息的场景下,去证明txsender有权力去花费一些note,并且这些note都是有效的。输入分为两个部分,一个是primary input, 一个是Auxiliary input。primary input是公开的输入信息,Auxiliary input是隐私的输入信息,只有txsender知道。具体内容如下图所示:
根据上图可知,spend zkproof总共证明了以下几点: Note commitment integrity:inputnode的承诺的完整性,证明cm确实根据v,rcm,gd,pkd计算出来的; Merkle path validity:默克尔树验证路径有效性,证明cm是存在默克尔树上的,是一个有效的cm; Value commitment integruty:inputnote v的承诺完整性,证明cv确实根据rcv,v计算出来的; Small order checks:证明私有参数,gd和ak是合法的; Nullifier integrity:Note的唯一标识,证明nf确实根据nsk,cm,pos计算出来的; Spend authority:Note的花费权力,证明拥有花费note所需的私有参数; Diversified address integrity: 一次性地址的计算完整性。 若以上等式均能满足,则说明txsender有权力花费对应的Note,因为等式4,6,7成立;其花费的note是有效性,因1,2,3,5成立。
2. output zkproof
output zkproof 主要是实现了在不暴露任何隐私信息的情况下,去使得validator相信txsender所产生的新note是有效的。输入仍分为两个部分,一个是primary input, 一个是Auxiliary input。primary input是公开的输入信息,Auxiliary input是隐私的输入信息,只有txsender知道。具体内容如下图所示:
根据上图可以看出,output zkproof总共证明了一下几点: Note commitment integrity:outputnode的承诺的完整性,证明cm确实根据v,rcm,gd,pkd计算出来的; Value commitment integruty:inputnote v的承诺完整性,证明cv确实根据rcv,v计算出来的; Small order checks:证明私有参数,gd是合法的; Ephemeral public key integrity:临时公钥的计算完整性。 若以上等式均满足,则说txsender产生的新note是有效的,因为等式1,2,3均成立;等式4成立则可以保证txreceiver可以根据自己的ivk密钥和epk去解析加密后的np,并保存到本地的集合当中。
3. spendAuthSig
关于spendAuthSig 的意义,可在两种场景下,进行描述。 第一:txsender自己产生zkproof,然后对spendDescription进行签名。这时,如果存在一个攻击者,想对spendDescription进行重放攻击,则其需要重新签名,则rk会被替换,那么验证者在验证spend zkproof时,就会验证失败;如果攻击者不替换rk,那么spendAuthSig的验签就会失败,因此spendAuthSig的存在,有效规避spendDescription的重放攻击; 第二:txsender调用第三方产生zkproof,然后自己对spendDescription进行签名,这是Sapling版本允许的,为了让内存和计算能力受限的一些钱包也能支持隐私交易,即使这样损失了隐私性,因为需要把auxiliary input全部发送给第三方。因此,在这种情况下,为了不让第三方恶意产生有效的zkproof,txsender需要对spendDescription进行签名,需要注意的是,txsender签名用的是ask,zkproof中spend Authority的证明用的是ak(ak可由ask计算得出),因此第三方无法产生有效的签名,有效规避spendDescription的重放攻击。 spendAuthSig的签名流程如下图所示:
4. bindingSig
如前面所说,bindingSig主要实现了两个功能。 第一:在不暴露spend Transfer 和 output Transfer的v值的情况下,保证了transaction balance; 第二:防止了outputDescription被攻击者重放,主要是利用spendDescription 和 outputDescription对应的用于计算cv的随机数rcv来产生签名私钥bsk,这使得攻击者无法作恶,因此签名验证公钥是利用spendDescription 和 outputDescription对应的cv来生成的,攻击者无法改变cv,否则zkproof会验证失败。 bindingSig的签名验签流程如下图所示:
Receive Transation
txReceiver接收交易的一般步骤为: 接收者遍历每笔交易的outputDes,用自己的ivk和outputDes里的epk尝试解密每一个Cenc ,如果返回成功,则将接收到的note添加至本地的receiveSets。 那么什么是Cenc呢?用ivk和epk如何去解密Cenc?1. 什么是Cenc?
Cenc是encCiphertext,是noteplaint经过对称密钥加密后的密文信息,noteplaint是指交易新生成的note的内容,这些内容都是私密的。np的组成及Cenc的加密过程如下图所示:
相关字段解释如下 DiverfiedHash:一次性参数生成器,输入d,输出gd,每次调用都不一样; esk、epk:一次性私钥、公钥,满足epk = esk * gd; pkd:一次性传输地址; np:noteplaint{memo、rcm、v、d} => note信息{特殊字段,由交易发送者和接收者协商一致使用、生成cm的随机数、note的面额、 diversifier}; KA.DerivePublic:计算公钥; KA.Agree:计算共享密钥; KDF:密钥获取函数,得到最终的加密密钥Kenc; Sym.Encrypt:一次性对称加密函数; 其中Kenc为一次性对称加密密钥,Penc为编码后的Cenc。从交易结构里可以看出,Kenc并没有直接的当作明文进行传输,那么,交易接收者是如何获取Kenc,对Cenc进行加密的呢?
2. 用ivk和epk如何去解密Cenc?
首先,让我们关注两个等式: pkd = ivk * gd esk * gd = epk 在加密的过程中,KA.Agree的输入参数为pkd和esk,由pkd * esk = ivk * gd * esk = ivk * epk,因此在解密的过程中,如果能输入ivk和epk,那么由KA.Agree(pkd,esk) == KA.Agree(ivk,epk)。理解了这一点,下面具体看一下Cenc的解密过程,如下图所示:
相关字段解释如下:
NoteCommit:cm计算函数,原始输入为np的数据; cm:note的承诺; Extractor:抽取器,返回cm的u坐标,cm形式(u,v); 若返回的cmu与outputDes里的一致,则说明证明者有计算cm的私有数据;
总结
1. Sapling中spendDescrption部分关于spendAuthSig的理解。a. 目的:证明某个人对于inputnote具有花费的权力,即拥有spendKey
b. 疑问:在spendDes的zkproof中,证明花费权力如下:
spend authority: rk = spendAuthSig.RandomizePublic(a,ak) (1)
由于a、ak都是Auxiliary input,是私有数据。且ak = spendAuthSig.DerivePublic(ask) (2),ask也是私有数据,因此若公式(1)成立,意味着此人有相应花费权力。那spendAuthSig存在的意义是啥?
c. 解答:在sapling版本,考虑到一些计算能力和内存空间受限的钱包,不具备生成proof的能力,因此可能需要第三方代理生成,此时,需要把ak、nsk等生成证明需要的私有数据公开给第三方,这样就会损失隐私性,在这种情况下,为了保证第三方不能随意生成一个有效的zkproof,交易发起者需要对整个spendDes用私钥进行签名。一个需要注意的点是:生成zkproof需要ak,不需要ask,ask是在签名时使用。因此第三方无法生成一个有效的签名。
2. 为何由sprout的joinsplit transfer 演变成sapling的spend transfer & output transfer。
a. 生成proof的大小变小了,joinsplit[1698bytes] > spend[384bytes] + output[948bytes]
b. balance证明不在zkproof中实现,减少了电路的复杂性,可改善生成和验证性能
3. spend 和output proof 均为验证balance属性,怎么保证整体value平衡。
使用了 pederson value commitment方法,它具有同态加法属性,即在不暴露v值的情况下,验证:
∑vold - ∑vold = vbalance
4. Sapling接收者如何接收note。接收者遍历每笔交易的outputDes,用ivk和outputDes里的epk尝试解密每一个Cenc ,如果成功,则计算note并添加至receiveSets
5. BindingSig。
关于这个签名的实现,您可参考协议说明文档4.12章节,密钥对不是重新生成的,而是基于cv和rcv的生成关系,实现签名验签过程
6. 如何隐藏交易发送者?
每笔交易的验证公钥都是一次性临时公钥,因此矿工不知道交易发起者。
7. 如何隐藏交易接收者?
交易结构中不存在交易接收者的地址信息,用交易接收者的隐私地址去生成对称密钥,生成Cenc ,交易接收者用问题4的方法接收交易。且同一交易接收者暴露给不同交易发起者的地址是不同的,为了防止交易发起者之间串通作恶。
8. 如何隐藏v值?
利用pederson value commitment进行同态隐藏。
以上是个人理解,如果错误,还希望各位读者批评指正。。多谢^_^。最后附上一张整体的结构图,希望能帮助大家理解。
图片超过2M,有需要的可以看资料私信我。
附录
1. ZCASH 官方协议说明书 https://github.com/zcash/zips/blob/master/protocol/protocol.pdfBitcoin Price Consolidates Below Resistance, Are Dips Still Supported?
Bitcoin Price Consolidates Below Resistance, Are Dips Still Supported?
XRP, Solana, Cardano, Shiba Inu Making Up for Lost Time as Big Whale Transaction Spikes Pop Up
XRP, Solana, Cardano, Shiba Inu Making Up for Lost Time as Big Whale Transaction Spikes Pop Up
Justin Sun suspected to have purchased $160m in Ethereum
Justin Sun suspected to have purchased $160m in Ethereum