Bulletproofs和Plonk等ZKP系统中Fiat-Shamir实现漏洞Frozen Heart

1. 引言

Trail of Bits团队近期发布Coordinated disclosure of vulnerabilities affecting Girault, Bulletproofs, and PlonK,指出Bulletproofs和Plonk等ZKP系统中的Fiat-Sharmir实现存在漏洞,使得恶意用户可为随机statement伪造proof。Trail of Bits将该漏洞命名为Frozen Heart,其中Frozen代表FoRging Of ZEro kNowledge proofs,Heart是指Fiat-Shamir transformation是很多proof system的核心。【该漏洞本质就是,作弊的Prover可就实际不知道的witness伪造证明。】

Trail of Bits提前通知了相关团队修复了该漏洞之后,才进行了公开披露。受影响的库主要有:

  • ZenGo的zk-paillier:已打补丁。
  • ING Bank’s zkrp (该库目前已删除)
  • SECBIT Labs的 ckb-zkp
  • Adjoint, Inc.的 bulletproofs:
    在 Bulletproofs论文 中,作者推荐了一种不安全的Fiat-Shamir生成方式。该作者已在论文最新版本中更新了该问题,在 y y y的计算中引入了statement s t st st。(可参看博客 Bulletproofs: Short Proofs for Confidential Transactions and More学习笔记。)
    Bulletproofs和Plonk等ZKP系统中Fiat-Shamir实现漏洞Frozen Heart_第1张图片
  • Dusk Network的 plonk:已打补丁
  • Iden3的 SnarkJS:已打补丁
  • ConsenSys的 gnark:已打补丁

因Fiat-Shamir实现引起的漏洞问题并不新鲜,如:

  • 2016年论文 How not to Prove Yourself: Pitfalls of the Fiat-Shamir Heuristic and Applications to Helios
  • 2020年论文 When is a test not a proof?

2021年2月博客 Serving up zero-knowledge proofs中以乒乓球评级形象描述了ZKP系统中的commit->challenge->prove流程,以及ZKP系统的soundness含义。

借助Fiat-Shamir transformation,可将ZKP的interactive交互 转换为 non-interactive。实现方法是引入哈希函数,将哈希函数看成是a random oracle。因此,选择哈希函数的输入则至关重要。仍然以打上面的乒乓球评级为例,若wall的内部随机数仅依赖speed和spin,而不依赖于位置,则具有相同speed和spin,打到wall上不同位置的球将返回到相同的位置,即相当于Prover获得了相同的challenge,这样这些challenge就不再是真正随机的,使得Prover可打破ZKP方案的soundness。

也就是说,哈希函数输入参数的小差别,可能会引法协议的严重安全后果。

2. sigma protocol中的错误实践

sigma protocol协议可参看:

  • 基于Sigma protocol实现的零知识证明protocol集锦

以一个简单的sigma protocol——Schnorr protocol为例,针对的场景为:

  • public info: g , Y g,Y g,Y
  • witness: X X X
  • 待证明relation: Y = g X Y=g^X Y=gX

针对上述场景的interactive版本证明过程为:

  • 1)Prover:生成随机数 A A A,计算 B = g A B=g^A B=gA,将 B B B发送给Verifier;
  • 2)Verifier:给Prover发送random challenge C C C
  • 3)Prover:发送proof Z = A + C X Z=A+CX Z=A+CX给Verifier;
  • 4)Verifier:验证 g Z = B Y C g^Z=BY^C gZ=BYC是否成立即可。

借助Fiat-Shamir实现的non-interactive版本证明过程为:

  • 1)Prover:生成随机数 A A A,计算 B = g A B=g^A B=gA
  • 2)Prover:采用哈希函数生成random challenge C C C
  • 3)Prover:发送proof Z = A + C X Z=A+CX Z=A+CX B B B给Verifier;
  • 4)Verifier:采用(相同输入的)哈希函数生成random challenge C C C,验证 g Z = B Y C g^Z=BY^C gZ=BYC是否成立即可。

关键在于,Prover是如何生成随机值 C C C的呢?在interactive版本中,Prover会将 B B B发送给Verifier,因此,可选择 C = H a s h ( B ) C=Hash(B) C=Hash(B)——这就是理论学家所称的弱Fiat-Shamir transformation,正如你可能怀疑的那样,这会产生一些微妙的后果。在实践中,敌手可提供a valid proof for some public key even if they don’t know the secret key,具体为:

  • 1)令 P K ′ PK' PK为某个Prover不知道私钥的公钥。
  • 2)令 B = P K ′ , C = H a s h ( B ) B=PK',C=Hash(B) B=PK,C=Hash(B)
  • 3)选择随机数 Z Z Z
  • 4)令 P K = ( g Z / P K ′ ) 1 / C PK=(g^Z/PK')^{1/C} PK=(gZ/PK)1/C。【由于不知道 P K ′ PK' PK的私钥,自然也不知道 P K PK PK的私钥。】

这样,敌手就可声称其知道 Y = P K Y=PK Y=PK的私钥(其实并不知道),在上面的non-interactive版本证明中,设置 B = P K ′ B=PK' B=PK和在步骤3)中已预取的 Z Z Z,使得Verifier验证 g Z = B Y C g^Z=BY^C gZ=BYC仍能通过。从而破坏了ZKP的soundess——不知道私钥 X X X的Prover可提供forged proof。


为解决该问题,计算 C C C的方式应为:【强Fiat-Shamir transformation】

  • C = H a s h ( B , Y ) C=Hash(B,Y) C=Hash(B,Y)
  • C = H a s h ( B , Y , g ) C=Hash(B,Y,g) C=Hash(B,Y,g)

从而可保证soundness,使得Prover无法提供forged proof。

如Swiss的选举系统中,采用了ZK方案来生成a decryption proof,来证明an encrypted vote decrypts to the correct result。但是,在实际实现时,由于在Fiat-Shamir transformation时哈希函数的输入不完整,使得Prover可create false proof——即可将有效的选票修改为无效不计数。详细参看2020年论文 How not to prove your election outcome。

参考资料

[1] 2022年4月博客 Coordinated disclosure of vulnerabilities affecting Girault, Bulletproofs, and PlonK
[2] 2021年2月博客 Serving up zero-knowledge proofs

你可能感兴趣的:(零知识证明,零知识证明)