众目睽睽下隐身,zk-SNARK黑科技如何保护区块链隐私

今天我们来谈谈区块链中的隐私保护问题。


区块链的隐私性挑战


有朋友会说:什么鬼?你们不是在第一节课中说过了区块链中每个人的地址都是不实名绑定的么?而且比特币不也经常被用于黑市交易么?隐私性不是好到爆炸?这还能有什么隐私问题?


没错,区块链地址的隐私性确实要比银行账户之类的强。可以说:如果你真的想要在区块链中完全匿名的话,是比现实中用银行账户要更容易办到的。


但是,有一类区块链应用需要依赖于对你的区块链身份的信任和绑定。比如你的医疗记录,房产记录,结婚记录等等各类记录类的信息。要想实现这些记录在区块链上存储和操作(如医疗记录授权,房产转接,结婚离婚等等),就需要将一个区块链上面的地址和真实的“你”绑定在一起。当这种绑定发生的时候呢,就自然的涉及到了隐私的问题。目前区块链上的普通transaction都是完全公共可见的,如果不加以防护,你和谁结了婚,有多少房产,医疗记录的授权,保险理财,车辆登记等等等等就暴露在了众目睽睽之下。如果没有有效的隐私保护手段,区块链和真实世界的互动程度就会受到极大的限制。


远的不说,我们看看老董在发工资时遇到的难题:

月末了,又到了老董给员工们发工资的时候。然而老董发工资的方式比较特别,他是通过区块链发工资给员工的。那么按照目前区块链的操作,老董必须先向区块链上的所有人喊话:“我给员工小明发了10000块钱工资”,然后区块链上的每个人去验证这个公开的事实。但是这就很尴尬了,每个员工拿多少工资大家都看得清清楚楚。员工之间工资多寡一目了然,和谐的公司环境荡然无存。


那么问题来了,为了解决公司和谐的问题,我们需要这个发工资的区块链系统,具有以下两点特性:

老董给小明具体发了多少工资,除了小明,大家都不知道,只有小明能看到老董到底转了多少钱过来。


虽然大家不知道老董给小明发了多少工资,但大家都可以验证,老董的存款是足够发得出“这个不知道是多少的”工资的,从而实现区块链上的共识。


那么一个基于以上两点的简单推论就是,收到钱的员工,如果想花自己的工资,也可以只向收款人证明某次转账(消费)是多少钱,同时让所有其他区块链上的矿工和用户无法看到所花费的具体金额,但所有人都又能验证这比转账是“有效的”。


这个事儿乍听上去完全不可能搞得成啊。这事儿相当于,你告诉一个陌生人:“我知道一个小秘密,但是我不能告诉你这个秘密具体是什么,可是我可以让你相信我知道这个你不知道的秘密。”


那么我们就只能放任我们的隐私暴露在区块链的众目睽睽之下吗?我们坚决地说不!


这就要隆重推出我们今天的主角:zk-SNARK。它是一种非常适合区块链的零知识验证技术,可以让别人在不知道具体交易内容的情况下验证交易(或者是智能合约函数调用)的有效性。有了zk-SNARK,我们既保留了区块链互相不信任个体间的共识达成问题,又保护了交易隐私,简直就是在众目睽睽下原地隐身。


zk-SNARK的全称是zero-knowledge Succinct Non-Interactive Arguments of Knowledge (零知识,简洁,非交互的知识论证)。相信看到这个超长的鬼名字,各位看官可能和我当时的心情一样是崩溃的。


实际上,zk-SNARK这个技术确实很神奇,但是它的晦涩难懂也是出了名了,号称是只有干货密码学家才能完全理解的技术。当你翻阅zk-SNARK的文献,你会发现你这辈子都不会遇到的数学知识:群论,离散数学,椭圆曲线加密,椭圆曲线配对,知识系数假设, Diffie-Hellman 假设,逻辑电路和多项式电路的等价性等等等等。 幸好Victor这么多年书没有白读,还是理解这些数学知识的。


更重要的是,我将会抛开这些繁复的数学名词,用最接地气的方式给大家讲解。


各位读者只需要一点点初等数学的知识,就可以大致理解这个绝大多数人都看不懂的区块链隐私保护技术的大致核心。当然,Victor在这里会省略很多重要的细节,所以如果真的懂zk-SNARK的同学呢,希望你们能包涵这些有意为之的简化,具备高等数学知识的同学,欢迎留言讨论具体的技术细节。


zk-SNARK的应用


在正式深入zk-SNARK的之前,我们不妨先看看它有哪些实际的应用。Zcash 是第一个应用zk-SNARK技术的区块链,它能够提供完全隐私化和加密化的虚拟货币转账。完美解决了老董发工资的难题。


以太坊(Ethereum)目前也在试图把Zcash的隐私交易功能作为一个预编译合约链接到其上的其他智能合约中(由于如果不使用预编译,每个区块的gas限制将无法完成复杂的zk-SNARK运算)。这被称为ZoE (Zcash over Ethereum),不过即使做了预编译优化,他能提供的隐私验证能力非常有限。


尚未正式发布的Hawk是一个完全采取了zk-SNARK的区块链智能合约部署系统。


当然zk-SNARK所能提供的隐私化交易未来还会有很多其他领域的应用。一个例子是通过区块链进行的拍卖,每个参与竞标的人无需暴露自己的身份和标的具体内容,这将让更多类型的拍卖得以在区块链上实现。另一个例子是匿名选举,投票人无需暴露自己身份就可以在区块链上参与投票。此外,zk-SNARK还可以使能一些“选择性公开”的场景,比如你可以在区块链上证明你在某一个城市而不暴露你的具体位置。


zk-SNARK技术详解


在介绍zk-SNARK之前,我们不妨先来了解一下什么叫做零知识验证。其实这个没啥难的。给大家举一个生活中的例子。假设有一扇用密码上门的锁,小明想要向小红证明,小明知道这个锁的密码,但同时又不告诉小明密码是什么,这个怎么办呢?其实很简单是不是?小明只需要先让小红进屋等着,然后小红通过门上的猫眼看着小明在门外开锁,因为是透过猫眼,所以小红可以确定不是别人开锁,但同时无法看到小明输入的密码。当门被小明打开的时候,小红就可以确信,小明确实是知道这个门的密码的。但重要的是,同时小红并不知道密码到底是什么。在这个简单的故事中,小红对小明进行了一次“零知识验证”(zk-proof)。


这个故事告诉我们一个很重要的道理:所谓的零知识验证的哲学核心就是要验证“使用一个秘密(钥匙)所产生的效果(门开了)”并且要保证这个效果(门开了)是只能通过使用这个特定的秘密(密码锁的密码正确)而产生的。这是最最重要的一点。


我们之前提到zk-SNARK是一种特别适合区块链的零知识论证 算法(论证与验证并不完全一样,为了简洁,在本文中不对验证和论证作区分)。这里为什么说zk-SNARK特别适合区块链呢?因为zk-SNARK在实现零知识验证的同时还具有以下几个特点:

Succinct (简洁性):验证者(verifier)只需要少量计算就可以完成验证。这对于区块链非常重要,因为区块链上为了能够快速达到共识,每一个计算步骤不能过于复杂。


Non-interactive (非交互性):示证者(prover)和验证者(verifier)之间只需要交换极少量的信息即可完成整个验证过程。这对于区块链同样至关重要,因为区块链上节点众多,并且每个节点都需要每一笔对交易进行验证,所以验证过程必须只涉及极少量的信息交换,否则通信成本会非常巨大。


阅读以下内容需要一些简单的数学知识。


为了理解zk-SNARK是怎么工作的,我们先考虑一个非常简单的场景:Alice想要向Bob证明她知道一组数x和y使得x+y=7,同时不让Bob知道x和y的具体数值。


一个简单的办法是使用一种神奇的“加密函数”E(x),这种加密函数有三个重要性质:

如果x,y不同,那么它们的加密函数值E(x)和E(y)也不相同。

给定E(x)的值,很难反推出x的值。

给定E(x)和E(y)的值,我们可以很容易地计算出某些关于x,y的加密函数值。比如,我们可以通过E(x)和E(y)计算出E(x+y)的值。

在这里,我们不深入讨论这种加密函数是什么,有一定抽象代数知识的读者可以去查看原始zk-SNARK的论文[1](事实上,椭圆曲线配对也是zk-SNARK的一个重要创新)。


有了这种加密函数,我们就可以很容易地设计出以下验证方案1.0:

Alice把E(x)和E(y)的数值发给Bob,

Bob通过收到的E(x)和E(y)计算出E(x+y)的值 (利用了加密函数的性质3),

Bob同时计算E(7)的值,如果E(x+y)=E(7),那么验证通过,否则验证失败。

由于加密函数的性质1,如果E(x+y)=E(7),则必然x+y=7成立,验证有效;同时由于加密函数的性质2,Bob无法从E(x),E(y)反推出x,y的具体数值。因此,Alice在不泄露x,y具体数值的情况下向Bob验证了x+y=7。


但是上述方案没有完全实现“零知识”,因为E(x)和E(y)还是泄露了一些关于x和y的信息。比如我们限定x,y为正整数,则Bob可以穷举所有相加为7的数字组合,然后把这些数字组合与收到的E(x), E(y)进行对比,从而获得x,y的具体数值。解决这个问题的方法是Alice产生一个秘密的随机数t,然后发送x+t和y-t的加密函数值E(x+t), E(y-t)给Bob。由于(x+t)+(y-t)=7,所以Bob那里仍可以验证通过,同时由于“随机偏移”t的引入,Bob无论如何也猜不到x,y的真实数值。


于是我们现在有了验证方案2.0:

Alice产生一个随机数t, 并把E(x+t)和E(y-t)的数值发给Bob,

Bob通过收到的E(x+t)和E(y-t)计算出E(x+y)的值,

Bob同时计算E(7)的值,如果E(x+y)=E(7),那么验证通过,否则验证失败。

以上方案实现了完全的“零知识”验证,看似我们的问题已经解决了,可真的是这样吗?


很可惜并不是!上面这个算法的问题在于它只能验证一些非常简单的知识(不过在实际中这个验证协议已经非常有用,比如RSA加密协议)。而在实际的区块链操作中,需要验证的知识可能是非常复杂的。在很多时候,以上这种仅仅依赖加密函数的方案就不够用了。


接下来我们考虑一个稍微复杂一点的场景:Alice需要向Bob证明她知道一个满足一定性质的秘密多项式P(x),并且不泄露具体这个多项式P(x)是什么。


注意了,这个多项式验证问题非常重要!我稍后会提到:

无论多复杂的验证问题都可以最终简化为一个多项式验证问题!

无论多复杂的验证问题都可以最终简化为一个多项式验证问题!

无论多复杂的验证问题都可以最终简化为一个多项式验证问题!

重要的问题说三遍。


下面我们来看如何修改之前的验证算法来解决多项式验证的问题。


先给大家先补习一下数学知识,一个度为d的多项式P(x)可以写成以下形式:

P(x) = a0 + a1x + a2x2 + … +adxd


为什么之前利用加密函数的方案在这里不能直接套用了呢?一个原因是之前我们只需要验证一组具体的值满足一定性质(如x=1和y=6满足x+y=7),而这里的多项式中x的值可能有无穷多个取值,穷举所有的可能性会消耗大量的计算资源。一个巧妙的办法是与其验证所有可能的取值,我们让Bob随机选一个x的值(如x=s),然后Alice仅仅需要向Bob证明多项式P(x)在x=s这一点的取值P(s)满足某种性质。这个随机取样的方法之所以合理,是因为两个不同的多项式在大多数情况都是不相等的,比如两条不同的直线最多有一个相交的点。如果我们随机取一个点,两个不同的多项式取值相同的概率几乎可以忽略不计。采用这个随机取样的办法,验证工作的计算量就大大降低了,这就是zk-SNARK中 “Succinct (简洁性)”的实现办法。


另外和验证方案2.0一样,Alice需要引入一个“随机偏移” R(s)来使得Bob完全得不到任何关于P(s)的信息。注意P(s)+R(s)必须满足待验证的性质。我们在这里不具体介绍R(s)是如何产生的。


加上这个随机采样的办法,我们得到了验证方案3.0:

Bob向Alice发送一个随机点s,

Alice首先产生一个随机偏移多项式R(x),然后计算P(s)和R(s),并且把P(s)+R(s)的加密函数值E(P(s)+R(s))发给Bob,

Bob验证接收到的加密函数值E(P(s)+R(s))是否满足给定的性质。


但是验证方案3.0有一个重大缺陷。Bob直接把随机点s的取值发送给了Alice,而P(s)需要满足的性质又是公开的,这就意味着Alice即使不知道多项式P(x)是什么,她也完全可以找一个与P(s)不同但是仍然满足条件的值y,并把y的加密函数值E(y)发给Bob。这种情况Bob仍然会验证通过。怎么处理这个缺陷呢?一个简单的解决办法就是把随机点s加密发给Alice,但是这样做的坏处就是Alice无法计算P(s), R(s)及其加密函数值E(P(s)+R(s))了。为了让Alice仍能计算E(P(s)+R(s)),我们可以让Bob把E(1), E(s), E(s2), ..., E(sd)都发送给Alice。根据加密函数的性质3,Alice是可以根据E(1), E(s), E(s2), ..., E(sd)计算出E(P(s)+R(s))的数值的,同时随机点s的具体数值也没有暴露。


于是我们得到了验证方案4.0:

Bob选取一个随机点s,并向Alice发送一系列加密函数值:E(1), E(s), E(s2), ..., E(sd),

Alice首先产生一个随机偏移多项式R(x),然后根据收到的E(1), E(s), E(s2), ..., E(sd)计算E(P(s)+R(s))的值并发送给Bob,

Bob验证接收到的加密函数值E(P(s)+R(s))是否满足给定的性质。


不过仔细想想验证方案4.0也有个问题。因为Bob只在一个随机点s进行了验证,Alice完全可能是人品爆发恰好在s这一点蒙对了,而实际并不知道符合条件的多项式P(x)长啥样!那么Bob怎么验证Alice确实知道多项式P(x),而不是恰好蒙对的呢?答案仍然是随机化!


我们可以让Bob在产生随机点s的同时再产生一个随机数k,然后向Alice同时发送关于s和k的信息。之后Bob要求Alice返回两个数,一个是P(s)的加密值E(P(s)),另一个是kP(s)的加密值E(kP(s))。注意k是一个只有Bob自己知道的秘密随机值,如果Alice可以同时告诉Bob关于P(s)和kP(s)的信息,则证明Alice不是瞎蒙的,而是确实知道P(x)这个多项式长啥样。具体原因是由于一个叫“知识系数假设” (Knowledge of Coefficient Assumption)的数学假设,我在这里就不具体叙述了。


现在我们有了验证方案5.0 (最终方案):

Bob选取一个随机点s和一个随机系数k,并向Alice发送两串加密函数值:[E(1), E(s), E(s2), ..., E(sd)], [E(k), E(ks), E(ks2), ..., E(ksd)],

Alice首先产生一个随机偏移多项式R(x),然后根据收到的[E(1), E(s), E(s2), ..., E(sd)], [E(k), E(ks), E(ks2), ..., E(ksd)]计算E(P(s)+R(s))以及E(kP(s)+kR(s))的值并发送给Bob,

Bob验证接收到的加密函数值E(P(s)+R(s))是否满足给定的性质,并且验证收到的另一个加密函数值是不是E(kP(s)+kR(s))。


以上基本就是zk-SNARK的完整验证流程了。不过最后还有几个重要的设计细节需要提一下(相信我,这真的是最后了)。


第一,我们注意到Bob(验证者)需要发送给Alice(示证者)的信息是不随验证内容变化的,因此可以事先在区块链中一次性设置好,之后任何验证过程都可以复用这个设置,验证者不再需要向示证者发送任何信息。这个事先设置好的信息被称为Common Reference String(CRS, 共同参考字符串)。一个重要的考虑是随机点s和随机系数k是必须严格保密的,否则就会有伪造证明通过验证。那么在实际中,这个随机点s和随机系数k是保存的呢?在Zcash的系统里,CRS中存放的实际上只是随机点s和随机系数k的一系列加密值,而s和k的明文则由6个“被充分信任的人”私下保存,这6个人处在地球上6个不同的位置,这些机密的随机数被拆开保存在这6个人手上,只要不是这6个人都变成“坏人”,这些随机数信息就不会被完整恢复。一个有意思的故事是,这6个“被充分信任的人”在最初的时候举行了一个神圣的仪式,共同参与并见证了这个随机点s和随机系数k的产生。


第二,以上我们只是讨论了多项式验证的问题。但是实际我们要验证的交易程序可能是非常复杂的。zk-SNARK提供了一个系统化的方法可以把任何验证程序转化成一个叫Quadratic Span Program (QSP)的多项式验证问题。有兴趣的读者可以阅读参考文献[2]。


zk-SNARK的不足与缺陷


之前说了zk-SNARK那么多的好处,那么它目前有没有什么缺陷呢?那必然是有的。


第一个问题:虽然zk-SNARK通过随机采样的方式大大减小了验证工作的计算量,但是由于需要验证一个较为复杂的多项式性质,其和传统的验证过程相比仍然耗费了更多了计算资源。这仍是目前很多区块链无法承受的计算需求。因此,如何针对zk-SNARK进行计算优化仍是一个开放问题。


第二个问题:我们提到zk-SNARK有一个初始设置的阶段,来生成“绝对机密”的随机信息。目前这些绝密随机信息的生成和保存仍然非常原始(参见之前提到的神秘仪式),很难让人完全放心,也很难进行拓展。比如,未来每一个需要隐私保护的智能合约可能都会有自己的初始随机信息要生成,如何确保这些初始随机信息不会被坏人泄露?同时业界和学术界也在研究如何在zk-SNARK中避免这个让人诟病的初始设置步骤。


参考文献

[1] Ben-Sasson, Eli, et al. "Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture." USENIX Security Symposium. 2014.

[2] Gennaro, Rosario, et al. "Quadratic span programs and succinct NIZKs without PCPs." Annual International Conference on the Theory and Applications of Cryptographic Techniques. Springer, Berlin, Heidelberg, 2013.

转载于:https://my.oschina.net/wdyoschina/blog/1570082

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值