Zerocash: 数字货币领域的暗科技

自从Zcash(一种新兴的匿名数字货币)由2016年11月正式上线以来,我一直在关注它的进展。起初的动机很单纯,只是觉得这项黑科技特别高大上,特别神秘:仅仅通过发送一些信息到公网,就可以实现两个匿名用户之间完全隐私的转账: 不仅付款人和收款人的身份保密,甚至连交易金额都完全保密!这种完全匿名究竟是怎么实现的?


Zcash其实可以看作是比特币的加强隐私版: 我们已经知道比特币可以实现点对点之间的快速低费用转账,而不需要通过银行或第三方机构(如支付宝,微信等等)。它在比特币的基础上, 实现了两项创新:转账金额保密 以及 完全匿名交易。可以这么说: Zcash是密码学领域的两项黑科技 -- 区块链(blockchain)技术和简短零知识证明(zk-SNARK)的一次联姻。


Zcash的实现有两种方式:可以完全开辟一个新区块链,也可以依附在比特币的区块链上。下面介绍的是第二种实现方式。依附在比特币上有一个好处: 允许用户在ZEC (Zcash的货币单位) 和比特币之间自由转换。


Zcash的两种交易: Mint (铸币)和 Pour (转账)。

铸币交易(Mint )

先来看铸币的功能:假设我有v单位的比特币,如何转换成ZEC呢?

我们先来回忆一个标准的比特币交易内容:

A: 我要转账 y 比特币給B, z 比特币给C, 我的 x = y +z 比特币来源于早前的 block K 交易 T。

这里假设的情形是: 作为一个用户A, 我需要向两个用户B,C转账。

最重要的步骤是, 我需要通过一个身份验证, 来证明我确实拥有block K 交易 T 的比特币的所有权。比特币里是这样实现所有权验证的: 假设在上个月 block K的交易T中, 用户D转给了我 x 比特币。为了保证只有我可以动用这笔金额,D会在交易内容中加入一个数字签名验证函数,确保只有我可以通过这个验证。

然后我需要提供 B,C 的地址。当然这里提到的地址不是B,C的家庭住址,而是他们的公钥。 同时,我还需要确定转账金额。 在最后一步, 我要对整个交易内容进行数字签名。现在交易(在我的电脑上是一个字符串)已经生成成功,可以发送到比特币公网上去了!回忆结束~~~~



Zcash上的铸币交易可以采取如下的形式: 我们假设用户A需要把面值为v的比特币转化成ZEC。A会首先随机生成三个字符串 r, s, \rho,然后使用一个commitment scheme来计算两个字符串 cm 和 sn,细节如下图。


(图片来自Zerocash: Decentralized Anonymous Payments from Bitcoin)


所以ZEC币是完全数字化的,一枚币只不过是一个向量 (a_{pk}, v, r, s, \rho, cm, sn)。其中 v 是这枚ZEC的面值,而cm, sn是用于记录ZEC币的生成和消费历史的,在下面我们还会再次回到这两个重要的数值。




然后 A 在比特币的公网上公开如下的交易内容:

A: 我需要用v比特币来铸造金额为v的ZEC, 我的commitment是cm, 我的v比特币来源于比特币账本上的第K个block的第T个交易。

注意:这里A仅仅公开了自己的cm和v, 而ZEC的其他信息只有A自己才知道。


Pour交易

Okay! 现在我们已经成功地铸造了一枚ZEC。然而新的问题也随之而来:怎么花掉它呢!?!?这就要转到Pour交易了。Pour是Zcash的核心创新, 可以说他是Zcash和比特币的本质区别。Pour的基本功能是:摧毁一个ZEC, 创造两个新ZEC, 满足金额守恒条件
两个新ZEC的面值之和 = 输入的ZEC的面值。

这两个新ZEC币可以被匿名收款人接收,而且(!)在交易中的所有数额都对公网保密。

那么Pour是如何实现的呢? 我们用一个实际生活中的情况来举例说明。还记得在Mint中我得到了一个面值为 v的ZEC吗?假设我到SF市参加密码学会议,在一个当地的支持ZEC的咖啡馆买了一杯咖啡:假设咖啡的价格为y ZEC, 那么我需要在交易中付给咖啡店 y , 并且付给自己 v - y (找回的钱)。从我原有的ZEC开始:


{\bf c} = (a_{pk}, v, r, s, \rho, cm, sn)

首先我需要向咖啡店小哥问到他们的地址b_{pk},然后我用和铸币相似的手段,生成两个新币

{\bf c_1} = (b_{pk}, y , \rho_1, r_1,s_1, cm_1)

(这个币将会转给咖啡店)

{\bf c_2} = (a_{pk}, v- y, \rho_2, r_2, s_2, cm_2)


(这个币找给自己)。

虽然这两个新币和{\bf c}看起来十分相似,但它们之间有着本质区别的~~


这个区别在于对币{\bf c_1}{\bf c_2}, 序列号sn不见了! 我们实际上来到了理解Pour交易的第一个关键点:先回忆一下这个“序列号”是怎么计算出来的:

sn = PRF(a_{sk}, \rho)

(这里PRF是一个给定的伪随机函数)。现在我们就能看出来,要计算这个序列号,需要两项

信息:第一项是ZEC生成的时候选取的随机数 \rho , 第二项是收款人的地址密钥。由于Zcash的设计,在使用任何一枚币的时候是需要出示序列号的。 所以除了收款人本人以外,任何人都无法出示正确的序列号,也就无法使用!

那么细心的各位肯定要问了:收款人虽然有密钥a_{sk} , 但是 \rho 在付款人手中啊,这样岂不是谁都花不了这笔钱?确实是这样。所以付款人还要把 \rho 用一种可靠的途径发给收款人。这个发送的方式就多种多样了:可以在用加密的电子邮件传送,或者可以面对面传递小纸条,...

然后我将如下交易信息发送到公网上: TX_{pour} = (sn, cm_1, cm_2, \pi). 这里注意:我需要向所有人出示自己的序列号sn(证明我确实是币{\bf c}的所有人), 以及生成两个新币的Commitments。那么最后的这个\pi是什么呢?它是一个确保我在整个交易过程中的计算诚实可靠的 --- 零知识证明。 关于这个零知识证明是什么?它又怎么样确保我没有在交易中作弊(比如确保我有足够多的钱来完成这笔交易, i.e., v \geq y) ? 请期待下回分解~

(题图来自 Zcash blog )

编辑于 2017-02-14