作者:林冠宏 / 指尖下的幽灵

博客:http://www.cnblogs.com/linguanh/

掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8

GitHub : https://github.com/af913337456/


注:发现掘金的图片屏蔽了博客园获取,导致我的一些文章在博客园这里的图片显示不了,因为现在我的文章是我首发在掘金的

目录

  • 前序
  • 交易体的结构 note
  • commitment 和 nullifier
  • ZCash 1.0 的公私钥机制
  • 转账人发出交易 note
  • 收款人如何获取 note 的使用权
  • 零知识自证
  • 后记

前序

在这篇文章中,我将承接上一篇文章 详细讲解:零知识证明 之 zk-SNARK 开篇 (开篇中介绍了什么是零知识证明及其它术语) 来从一个完整的交易流程 讲解 ZCash 是如何利用零知识证明zk-SNARK 实现匿名交易的。

其中第部分 收款人如何获取 note 的使用权 是目前国内网上所有的介绍 ZCash 的文章都没有谈及的,造成了读者只知道交易的发出,而不知道交易是凭借什么机制让收款人有权限使用的

此外,"现在关于 ZCash 的文章和回答,很多都不准确,甚至是有误导性的!"此话---引自 woodstock

文章不从源码分析的角度去展开,那样的写作和阅读成本太高。

交易体的结构 note

首先 ZCash 在交易的整体模式上,参考了 BTCUTXO 模型,拥有交易输入和交易输出的概念,对于 UTXO 的讲解,可以自行网上搜索文章进行阅读,目前介绍 UTXO 的优秀文章还是很多的。

UTXO 是一种模型,模型是可以被以不同的形式展现出的。在 ZCash 中,交易原始的输入输出结构体被形象成了代码中的 note 结构体。

一个完整的 note 包含有如下的变量:

  • 持有者的公钥: a_pk,又称收款人地址
  • 面额: value,又被简称为 v,代表这笔 note 的代币数值
  • 随机数: rho, 是每一条 note 的唯一标识,当一条 note 被消费了之后,这个值会被放置到 nullifier 表中,代表这条 note 已经被消费了,再次进行消费同一条 note的时候,会触发双花 错误,即交易双花防护机制。
  • 随机数: r

用向量组代表上面的 note,可以表示为:note = <a_pk , v , r , rho>

commitment 和 nullifier

ZCash 中,存在两种表格,分别是:commitmentnullifier,下图取自于 ZCash 的官方文档 How Transactions Between Shielded Addresses Work 中,提示:该文章内部并没有指出 note 的收款人是如何对一笔 note 有使用权限的,看完也会有很多疑问。

图中显示出了 commitmentnullifier 表格的大致结构:

左边的 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 的公私钥机制

在认识交易被发出前的操作,我们现来认识下 ZCash 1.0 的公私钥机制,下图取自于官方文档:

下面我将讲解下这图的主要要表达的意思,上面我列举的 note ,是一个整体的讲解,在实际的 ZCash 源码中,note 其实还分为两种,分别是:SproutNoteSaplingNote。目前 ZCash 使用的是第一种,本文所谈的也是 SproutNoteZCash的发展将会慢慢向第二种 SaplingNote 迁移。

因为 note 结构中有一个 a_pk 字段,在SproutNoteSaplingNote中,内部的字段组成是不同的,源码的定义如下图所示:

SaplingNote 中,明显 a_pk 不见了,多了其它的。回到下图,我们主要看左边的 Sprout,其中:

  • 双竖线表示相同
  • 箭头表示生成关系,如果 A 指向B, 那么表示A可以生成B。

下图的Sprout 中 a_sk 代表的是私钥,由 a_sk 可以生成第一个公钥 a_pk私钥 sk_enc,由 sk_enc 可以生成第二个公钥pk_enc。意味着:

在ZCash 1.0 中,一个钱包地址里面包含由两个公钥:a_pk , pk_enc

转账人发出交易 note

现在进行到转账人发出交易 note,假设转账人是A,收款人是B,A 要转 5 个币个B。

那么 A 组装 note 的过程如下:

  1. 首先 A 找到自己的一条或多条没消费的 note,即是 UTXO 输出,每条 note 中有对应的 value,我们假设一条就足够转出,多条的情况是如果一条 note 无法满足目标转出 value,才会凑多条 note 作为输出。
  2. A 找出了 note 1 ,使用自己的 私钥 sk_enc 解密 note 1,获取 note 1 中的 value 和其它数据,假设 value 是8,此时8 > 5
  3. A 先新建两条 note,分别是 note4 和 note5,note4 内部的 value 设置为 5,代表是要给 B 的。note 5 的 value 是 (8-5=3),代表给自己找零,不找零将会损失掉这3个币,相关的找零解析见UTXO模型介绍。
  4. A 为 note 4 和 note 5 分别生成随机数 r4 和 r5
  5. A 将 B 的 a_pk 公钥设置到 note 4 里面去, 代表收款人是 B。再将自己的 a_pk 公钥设置到 note 5 里面去,代表收款人是自己。
  6. 使用 hash 函数生成 note 4 和 note 5 的 rho。PS: ( rho = nf = HASH (r) )
  7. 此时 note 4 和 note 5 分别是:

note4 = <B的a_pk ,v=5,r4,rho4>

note5 = <A的a_pk ,v=3,r5,rho5>

  1. 与此同时,A 还要将 note 1 的 nf2 (nf2=HASH (r1)) 发往公链的节点网络,即 note 1 的 rho,此时节点在收到 nf2 后会判断是否已经在 nullifier 列表存在 nf2 了,是的话,那么判断 note 1 被双花了。否则,就将 note 1 的 nf2 记录下来了。
  2. A 此时使用 B 的 pk_enc 签名 note 4,和自己的 pk_nec 签名 note 5。这里 B 的 pk_enc 是公开的,注意!ZCash 1.0 中,一个地址的 a_pk 和 pk_enc 都是公开的。
  3. A 将 note 4 通过秘密通道发给 B,自己的 note 5 便自己保存,同时将 note 4 和 note 5 的 hash 值 h4、h5 发给所有链上的节点。
  4. 以上便是一个发起交易的流程。

对上述流程可以提出下面细节。

  • 节点能够知道的只有 note1 的 nf2 和 note4 的 h4 和 note5 的 h5。他们对收款人地址,金额是多少都一无所知。
  • 此时链上节点们维护的 commitmentnullifier 表变成了如下的样子。
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)
  • A 发给 B note4 的秘密通道。这里我们不展开说,它的方式有很多,可以在用加密的电子邮件传送,或者可以面对面传递小纸条。具体见官方完整的文档:完整文档
  • B 手上有经过了自己的 sk_enc 签名了的 note4

收款人如何获取 note 的使用权

其实在上面小节中,读者应该能理会到 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 的 rho 后,如何判断发送者是真正对 note 拥有使用权的?

答:对于 note 的所有权拥有者A 来说,好像除了公布 note 里面的内容外,好像没其它手段来自我证明?这个时候零知识证明就排上用场了,note 的拥有者在发布使用该 note 的时候还要向节点出示称为 Π 的零知识证明凭据,根据 Π ,节点们作为验证者,能够验证 note 的使用权的确属于A。ZCash 在这里应用到了零知识证明,它的代码是根据zk-SNARK 理论完成的,同时也参考了 Zerocash

  • PS:如何统计一个地址的余额?

答:不在本文的讨论范围内,详细可以见官方完整的文档:完整文档第4章,关于 Balance 的描述。

后记

为了理清 ZCash 的匿名交易的最后一部分,也即是收款人是如何获得 note 的所有权的,使整个流程形成闭环

我查阅了很多文章都、文档和咨询了一位网友已经查看了部分源码。目前网上的其它文章都没有讲到 收款人如何获取 note 的使用权 这一部分。稍微较好的是对官方文档 在隐藏地址之间如何进行交易的直接做了翻译,但是由于官方的这篇文章是个简版,也没有对 收款人如何获取 note 的使用权 做出解析,所以,几乎所有的翻译文章都是没答案的,而且大部分文章,本身还有一些错误,可能作者自己也一知半解。

感谢下面的人和文给予了我有用的信息引导:

人:woodstock

文:

详细讲解:零知识证明 之 ZCash 完整的匿名交易流程的更多相关文章

  1. 详细讲解:零知识证明 之 zk-SNARK 开篇

    作者:林冠宏 / 指尖下的幽灵 博客:http://www.cnblogs.com/linguanh/ 掘金:https://juejin.im/user/587f0dfe128fe100570ce2 ...

  2. 一个数独引发的惨案:零知识证明(Zero-Knowledge Proof)

    导言:原文的作者是著名的Ghost和Spectre 这两个协议的创始团队的领队Aviv Zohar.原文作者说他的这篇原文又是引用了以下这两篇学术论文: How to Explain Zero Kno ...

  3. 详细讲解nodejs中使用socket的私聊的方式

    详细讲解nodejs中使用socket的私聊的方式 在上一次我使用nodejs+express+socketio+mysql搭建聊天室,这基本上就是从socket.io的官网上的一份教程式复制学习,然 ...

  4. 详细讲解Android对自己的应用代码进行混淆加密防止反编译

    1.查看项目中有没有proguard.cfg. 2.如果没有那就看看这个文件中写的什么吧,看完后将他复制到你的项目中. -optimizationpasses 5 -dontusemixedcasec ...

  5. node+vue进阶【课程学习系统项目实战详细讲解】打通前后端全栈开发(1):创建项目,完成登录功能

    第一章 建议学习时间8小时·分两次学习      总项目预计10章 学习方式:详细阅读,并手动实现相关代码(如果没有node和vue基础,请学习前面的vue和node基础博客[共10章]) 视频教程地 ...

  6. python编写shell脚本详细讲解

    python编写shell脚本详细讲解 那,python可以做shell脚本吗? 首先介绍一个函数: os.system(command) 这个函数可以调用shell运行命令行command并且返回它 ...

  7. Nginx基础详细讲解

    Nginx基础详细讲解 链接:https://pan.baidu.com/s/1xB20bnuanh0Avs4kwRpSXQ 提取码:migq 复制这段内容后打开百度网盘手机App,操作更方便哦 1. ...

  8. vue-cli 目录结构详细讲解

    https://juejin.im/post/5c3599386fb9a049db7351a8 vue-cli 目录结构详细讲解 目录 结构预览 ├─build // 保存一些webpack的初始化配 ...

  9. 30 道 Vue 面试题,内含详细讲解(涵盖入门到精通,自测 Vue 掌握程度)

    前言 本文以前端面试官的角度出发,对 Vue 框架中一些重要的特性.框架的原理以问题的形式进行整理汇总,意在帮助作者及读者自测下 Vue 掌握的程度.本文章节结构以从易到难进行组织,建议读者按章节顺序 ...

随机推荐

  1. ElasticSearch集群本机搭建

    ElasticSearch集群本机搭建 elasticsearch elasticsearch -Ehttp.port=8200 -Epath.data=node2 elasticsearch -Eh ...

  2. 进程间通信之-信号signal--linux内核剖析(九)

    信号及信号来源 什么是信号 信号是UNIX和Linux系统响应某些条件而产生的一个事件.接收到该信号的进程会对应地採取一些行动.通常信号是由一个错误产生的. 但它们还能够作为进程间通信或修改行为的一种 ...

  3. 百科知识 手机QQ的视频如何保存

    手机QQ上打开一个视频,然后进入播放界面,然后暂停播放   点击右上角的按钮,就可以保存到手机        

  4. Solidworks修改零件文件名之后工程图找不到零件怎么办

    如下图所示,如果我直接把"压紧柱 V1.0"改名为"压紧柱",则打开工程图之后图纸都没了.   即便你用打开零件的方式找到了这个零件,工程图还是老样子   所以 ...

  5. WheelView实现省市区三级联动(数据库实现版本号附带完整SQL及数据)

    近期在实现收货地址功能,用到了省市区三级联动效果,网上找到一般都是xml或json.数据源陈旧改动麻烦.改动了一下使用数据库方式实现了一下 数据源解决.因为数据量比較大通过初始化批量运行SQL的方式不 ...

  6. com.sun.jdi.InvocationException occurred invoking method 异常

    参考链接:https://stackoverflow.com/questions/4123628/com-sun-jdi-invocationexception-occurred-invoking-m ...

  7. MongoDB:分片(简介 & 自动分片 & 片键)

    分片(增加服务器,水平扩展)是MongoDB的扩展方式,通过分片能过增加更多的机器来应对不断增加的负载和数据,还不影响应用. [简介] 分片(sharding)是指将数据拆分,将其分散存在不同的机器上 ...

  8. 漫谈程序猿系列:无BUG不生活

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZm9ydW9r/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/d ...

  9. openwrt: firstboot

    # cat /sbin/firstboot #!/bin/sh /sbin/jffs2reset jffs2reset 是fstools里的工具.做的工作有: 在/proc/mtd里找到名为" ...

  10. JavaScript中label语句的使用

    之前在读<javascript高级程序设计>的时候,看到过lable语句,当时看完感觉好像很少用到,但是今天,刚好在项目终于到了合适的场景,合理使用label可以大幅度优化性能. 首先来简 ...