本文介绍了Zcash中隐蔽地址之间交易的基本原理,包括使用note表示coin,引入随机数r以增加隐私,以及使用Nullifier集合来区分已花费和未花费的note。同时,为了解决交易验证问题,Zcash引入了零知识证明(Zero-Knowledge proof),以确保交易的有效性和隐私性。
Created: <2023-03-18 Sat>
Last updated: <2023-04-08 Sat>
Zcash 是一种更加注重用户隐私的加密货币。Zcash 在两类地址:隐蔽地址(这类地址以“z”开头)和透明地址(这类地址以“t”开头)。在隐蔽地址之间的转账交易是完全隐私的:链上看不到发送者、接收者、转账金额。本文将介绍 Zcash 隐私交易的基本原理。
在 Zcash 中,一般使用术语 note 来表示 coin。这样,BTC 中的 UTXO 对应到 Zcash 中就是 unspend note。
为了表述简单,我们假设每个 note 恰好是 1 BTC,而且一个地址最多有一个 note。这样,在一个给定时间,Zcash 节点的数据库可由一个 unspend note 的列表来表示,如:
Note_1 = (PK_1), Note_2 = (PK_2), Note_3 = (PK_3)
假设 PK1 是 Alice 的地址,她想把她的 1 BTC note 转给 Bob 的地址 PK4 。她发送一个消息:“转移 1 BTC 从 PK1 到 PK4 ”给所有节点,并对这个消息使用 PK1 对应的私钥 sk1 进行签名。节点收到消息后,首先验证签名,然后检查 PK1 对应地址中确实存在 1 BTC note,最后更新节点数据库为:
Note_4 = (PK_4), Note_2 = (PK_2), Note_3 = (PK_3)
上面的过程目前没有隐私可言。假设每个 note 都包含一个随机数 r,后面将看到这会给我们带来隐私。引入随机数后,节点的数据库如下所示:
Note_1 = (PK_1, r_1), Note_2 = (PK_2, r_2), Note_3 = (PK_3, r_3)
为了实现隐私,自然地容易想到让节点不直接保存 note,而是保存某种方式加密(比如哈希)后的 note,也就是说节点的数据库为:
H_1 = HASH(Note_1), H_2 = HASH(Note_2), H_3 = HASH(Note_3)
为了实现隐私,我们不能直接删除已经花费的 note 的哈希,否则根据某个时间点被删除的哈希和新加入的哈希就可以找到一些对应关系出来。也就是说节点的数据库中将保存所有已经花费和没有花费的 note 的哈希。
但是这带来一个新问题: 如何区分已经花费和没有花费的 note 呢?办法是引入一个 Nullifier 集合(注: Zerocash 原始论文中的 Serial Number 就是这里的 Nullifier),它是已经花费的 note 关联的 r 值的哈希值。 这样,每个 Zcash 节点数据库中除了保存 note 的哈希集合外,还要保存另一集合:Nullifier 集合。比如,当 Note2 被花费后,节点的数据库如表 1 所示。
Hashed notes | Nullifier set |
---|---|
H1=HASH(Note1) | nf1=HASH(r2) |
H2=HASH(Note2) | |
H3=HASH(Note3) |
Table 1: 当 Note_2 被花费后,HASH(r_2) 会出现在 Nullifier set 中
假设 Zcash 的节点数据库如表 1 的示。Alice 拥有 Note1 ,她想转移 Note1 给 Bob,Bob 的公钥为 PK_4。为了简单起见,我们假设 Alice 和 Bob 之间有个私密通道可以传送只能让 Alice 和 Bob 知道的秘密(注:Zcash 并没有这个要求)。
简单来说,Alice 需要做两件事:一是发布一个 Nullifier,即 HASH(r1) 以表示她的 Note1 已经花费了,二是发布一个新的由 Bob 控制的 Note4 。
具体来说,Alice 转换 Note1 给 Bob 的过程如下:
Alice 随机选择一个随机数 r4 ,Alice 定义新 note 为 Note4=(PK4,r4) ;
Alice 通过私密通道把 Note4 发送给 Bob;
Alice 发送 nf2=HASH(r1) 给所有 Zcash 节点;
Alice 发送 H4=HASH(Note4) 给所有 Zcash 节点。
Zcash 节点收到 nf2 后,首先要检查 nf2 是否在 Nullifier set 中已经存在了(是否以前花费过),如果存在了则要拒绝;如果 nf2 在 Nullifier set 中不存在,则加入 H4 到 Hashed notes 中(注:直接这样做有问题,后面会介绍)。这时,Zcash 的数据库看起来如表 2 所示。
Hashed notes | Nullifier set |
---|---|
H1=HASH(Note1) | nf1=HASH(r2) |
H2=HASH(Note2) | nf2=HASH(r1) |
H3=HASH(Note3) | |
H4=HASH(Note4) |
Table 2: Alice 转换 Note1 给 Bob
上面过程有点问题!因为当 nf2=HASH(r1) 在 Nullifier set 不存在,只能说明 r1 对应的 note 没有花费过;但并不能说明 r1 对应的 note 确实属于 Alice。其实节点在收到 nf2 时甚至都无法检查 nf2 确实是某个值的哈希。当然, 解决这个问题最简单的办法是 Alice 直接公布 Note1 即公布 (PK1,r1) ,不过这样做就没有隐私可言了。
Zcash 引入 Zero-Knowledge proof 的目的就是解决这个问题。 除了上面步骤外,Alice 还需要公布一个 proof π ,这个 π 可说服所有 Zcash 的节点,Alice 知道 PK1,sk1,r1 的值,且它们之间满足下面要求:
Note1=(PK1,r1) 存在于 Hashed notes 中;
sk1 是 PK1 的私钥,从而确保 Alice 拥有 Note1 的控制权;
r1 的哈希是 nf2 ,从而确保往 Nullifier set 中加入的数据 nf2 确实和 Note1 相关。
能证明上面事情,且还不会泄露 Alice 的 PK1,sk1,r1 的信息,这是 Zero-Knowledge proof 的能力。
为了简单起见,上面只介绍了 Zcash 隐私交易的最基本原理,它和真实的情况有出入:
Hashed Notes 在 Zcash 中并不是一个 list,而是 Merkle tree,它是一种更有效的存储方式;此外其中保存的也并不是 Note 的 Hash,而是 Note 的 Commitment。
Zcash 中 Nullifier 的定义更加复杂一些。
Zcash 并不要求有私密通道。前面介绍的例子中要求 Alice 和 Bob 之间的存在私密通道,关于如何去掉对私密通道的依赖可以参考 Zcash 文档中关于 In-band secret distribution 的部分。
本文基本上是 How Transactions Between Shielded Addresses Work 的翻译(有少量删减),推荐读者阅读原文。
- 本文转载自: aandds.com/blog/zcash-pr... , 如有侵权请联系管理员删除。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!