做者:林冠宏 / 指尖下的幽灵git
博客:http://www.cnblogs.com/linguanh/github
GitHub : https://github.com/af913337456/函数
在这篇文章中,我将承接上一篇文章 详细讲解:零知识证实 之 zk-SNARK 开篇 (开篇中介绍了什么是零知识证实及其它术语) 来从一个完整的交易流程
讲解 ZCash
是如何利用零知识证实
的zk-SNARK
实现匿名交易的。源码分析
其中第六
部分 收款人如何获取 note 的使用权
是目前国内网上全部的介绍 ZCash
的文章都没有谈及的,形成了读者只知道交易的发出
,而不知道交易是凭借什么机制让收款人有权限使用的
。post
此外,"如今关于 ZCash 的文章和回答,不少都不许确,甚至是有误导性的!"
此话---引自 woodstock加密
文章不从源码分析的角度去展开,那样的写做和阅读成本过高。.net
首先 ZCash
在交易的总体模式上,参考了 BTC
的 UTXO
模型,拥有交易输入和交易输出的概念,对于 UTXO
的讲解,能够自行网上搜索文章进行阅读,目前介绍 UTXO
的优秀文章仍是不少的。翻译
UTXO
是一种模型,模型是能够被以不一样的形式展示出的。在 ZCash
中,交易原始的输入输出结构体被形象成了代码中的 note
结构体。3d
一个完整的 note
包含有以下的变量:
nullifier
表中,表明这条 note 已经被消费了,再次进行消费同一条 note的时候,会触发双花
错误,即交易双花防御机制。用向量组表明上面的 note,能够表示为:note = <a_pk , v , r , rho>
在 ZCash
中,存在两种表格,分别是:commitment
和 nullifier
,下图取自于 ZCash
的官方文档 How Transactions Between Shielded Addresses Work 中,提示
:该文章内部并无指出 note 的收款人是如何对一笔 note 有使用权限的,看完也会有不少疑问。
图中显示出了 commitment
和 nullifier
表格的大体结构:
左边的 hashed notes
就是 commitment
列表,右边的 nullifier set
就是 nullifier
列表。
commitment
列表存储的是全部的,注意!是全部。存储全部 note 通过不可逆 hash 函数后生成的 hash 值 Hx
x∈ (1,2,3,4,5,6...N)
nullifier
列表存储的是已经被消费
的 note 中的随机数 r
生成的 hash 值 nfx
。r 就是 note 结构中的 r。nullifier
中文意思:做废
,nullifier set
做废集合。
注意一点
:对于两个不一样的 note,他们的 commitment hash 值必定不相同,从 hash 值又没法推测出其背后的 note.。
如上图所示,在右边咱们能够看到 r2 对应的 note2 的 nf1 已经被记录到了 nullifier
列表中,这个 nf1 就是结构体中的 rho。被记录到了这里,表明着 note2 再也不是 UTXO
,再也不是没被花费的输出,它已经被消费了。
一条被花费的输出 output
会致使一条新产生的交易输入 input
。继续以上图为例子,note2 做为被消费了的输出,据表能够, note3 应该是它所产生的交易的输入,此时 note3 还没被消费,由于它的 nf3 还没被记录到 nullifier
列表。note2 相对于 note3 来讲,note2 是 note3 的输入。note3 做为一条新的交易输入,还没输出给其它的 note。
在认识交易被发出前的操做,咱们现来认识下 ZCash 1.0
的公私钥机制,下图取自于官方文档:
下面我将讲解下这图的主要要表达的意思,上面我列举的 note ,是一个总体的讲解,在实际的 ZCash
源码中,note 其实还分为两种,分别是:SproutNote
和 SaplingNote
。目前 ZCash
使用的是第一种,本文所谈的也是 SproutNote
。ZCash
的发展将会慢慢向第二种 SaplingNote
迁移。
由于 note 结构中有一个 a_pk 字段,在SproutNote
和 SaplingNote
中,内部的字段组成是不一样的,源码的定义以下图所示:
SaplingNote
中,明显 a_pk 不见了,多了其它的。回到下图,咱们主要看左边的 Sprout
,其中:
下图的Sprout
中 a_sk 表明的是私钥,由 a_sk 能够生成第一个公钥 a_pk
和 私钥 sk_enc
,由 sk_enc 能够生成第二个公钥pk_enc
。意味着:
在ZCash 1.0 中,一个钱包地址里面包含由两个公钥:a_pk , pk_enc
如今进行到转帐人发出交易 note,假设转帐人是A,收款人是B,A 要转 5 个币个B。
那么 A 组装 note 的过程以下:
UTXO
输出,每条 note 中有对应的 value,咱们假设一条就足够转出,多条的状况是若是一条 note 没法知足目标转出 value,才会凑多条 note 做为输出。私钥 sk_enc
解密 note 1,获取 note 1 中的 value 和其它数据,假设 value 是8,此时8 > 5
。找零
解析见UTXO
模型介绍。PS: ( rho = nf = HASH (r) )
note4 = <B的a_pk ,v=5,r4,rho4>
note5 = <A的a_pk ,v=3,r5,rho5>
nf2=HASH (r1)
) 发往公链的节点网络,即 note 1 的 rho,此时节点在收到 nf2 后会判断是否已经在 nullifier
列表存在 nf2 了,是的话,那么判断 note 1 被双花了。不然,就将 note 1 的 nf2 记录下来了。发起交易
的流程。commitment
和 nullifier
表变成了以下的样子。note hashs(commitments) | nullifier set |
---|---|
h1=HASH (note1) | nf1 = HASH (r2) |
h2=HASH (note2) | nf2 = HASH (r1) |
h3=HASH (note3) | |
h4=HASH (note4) | |
h5=HASH (note5) |
其实在上面小节中,读者应该能理会到 B 是可使用本身的原始私钥 a_sk 对本身获取到的 note4 数据进行解密的,进而获取到里面的 <a_pk,v,r,rho>,到了这一步,B 保存好 note4 的 rho,那么他就可以向 nullifier
表发送 note4 的 rho ,达到消费 note4 的目的。
至此,ZCash 的匿名交易流程造成了闭环
。
那么为何 a_sk
能对 sk_enc
签名的数据,进行解密呢?由于在 ZCash 1.0 中,由地址的公私钥生成规则,可知原始私钥 a_sk 能够导出 sk_enc。在ZCash 1.0 的公私钥机制
小节中也作了说明。
答:对于 note 的全部权拥有者A 来讲,好像除了公布 note 里面的内容外,好像没其它手段来自我证实?这个时候零知识证实
就排上用场了,note 的拥有者在发布使用该 note 的时候还要向节点出示称为 Π
的零知识证实凭据,根据 Π ,节点们做为验证者,可以验证 note 的使用权的确属于A。ZCash 在这里应用到了零知识证实
,它的代码是根据zk-SNARK
理论完成的,同时也参考了 Zerocash
。
答:不在本文的讨论范围内,详细能够见官方完整的文档:完整文档 的第4章
,关于 Balance 的描述。
为了理清 ZCash 的匿名交易的最后一部分,也便是收款人是如何得到 note 的全部权的,使整个流程造成闭环
。
我查阅了不少文章都、文档和咨询了一位网友已经查看了部分源码。目前网上的其它文章都没有讲到 收款人如何获取 note 的使用权
这一部分。稍微较好的是对官方文档 在隐藏地址之间如何进行交易的直接作了翻译,可是因为官方的这篇文章是个简版,也没有对 收款人如何获取 note 的使用权
作出解析,因此,几乎全部的翻译文章都是没答案的,并且大部分文章,自己还有一些错误,可能做者本身也只知其一;不知其二。
感谢下面的人和文给予了我有用的信息引导:
文: