隐私又公平!如何用 zkSNARK 做一款链上德扑游戏?
在过去一年多时间里,越来越多人意识到 ZK(零知识证明) 这种密码学工具的强大,我们也看到很多零知识证明应用的兴起,比如隐私社交、隐私投票、隐私DAO等等。实际上,零知识证明的应用非常广阔, 有链上隐私需求的应用都可能会用到零知识证明。
在刚刚结束的 ETHSanFrancisco 2022 期间的 ETHGlobal 黑客松活动中,Manta Network 密码学开发团队的小伙伴们就在短短36个小时的时间里做出了一款基于 zkSNARK 的德扑游戏,并在ApeCoin、ENS、SKALE、Optimism 主办的四个竞赛单元拿到奖项。
很多人所熟知的 Dark Forest(黑暗森林)就是基于 zkSNARK 的一款实时策略(非完全信息)游戏。非完全信息游戏即玩家不掌握全部状态的游戏,比如在扑克中,玩家手中的牌是私密信息,摸牌的过程也是完全隐私的。非完全信息的有趣之处就在于可以催生一系列复杂的游戏策略。
在公共区块链上,由于链上数据的公开透明,很难构建非完全信息游戏。但是,通过零知识证明技术,玩家可以保持在保持隐私状态的同时,公开提交可验证的有效动作。
在此次的黑客松活动中,Manta Network 基于 zkSNARK 构建了一款链上德扑洗牌和发牌系统。这套系统主要解决了链上德扑游戏中存在的两个问题:如何公平地进行洗牌以及如何隐蔽地在玩家间发牌(否则游戏可能会因为 MEV 问题而玩不下去)。
本质上,基于零知识证明的链上德扑,让发牌主体去中心化,庄家无法通过控制发牌来控制牌局。
在 Web2 中心化客户端里玩德扑,会遇到这样的情况,可能性极小的牌,刚好就发给你了。大概率能得到的牌,却出不来。
目的就是借发牌操纵牌局,让你的对手,在线下赢牌概率极低的情况下,在线上恰好赢你。
这就是为什么我们需要去中心化德扑。
ZKShuffle 系统有三个功能:
ZKShuffle.setup:每位玩家都生成一个密钥对,并将每个人对应的公钥放在一起生成一副聚合公钥。
ZKShuffle.shuffle_encrypt: 在进行洗牌时,每位玩家都需要依次调用 shuffle_encrypt。
为了保证加密和解密可以任意顺序进行,这里我们用到的是同态加密方案(Homomorphic Encryption scheme)。比如说,本局游戏中有三位玩家,在经过一轮加密后,每张牌都会有三个加密锁:Card{Alice, Bob, Charlie} 。
ZKShuffle.decrypt: 如果想要向一位指定玩家发牌,每个玩家都需要调用解密功能。比如说,如果游戏的逻辑是要将牌发给 Charlie,正确的顺序应该是:Alice 拿到加密牌Card{Alice, Bob, Charlie},用她的密钥进行解密,然后将解密后的牌 Card{Bob, Charlie} 在链上进行提交,同时提交一个零知识证明来验证解密的有效性。
Bob 在链上拿到Alice提交的这张部分解密的牌Card{Bob, Charlie}后,再用自己的密钥进行解密,并在链上提交这张牌 Card{Charlie} 以及验证解密有效性的零知识证明。最后 Charlie 就拿到了 Card{Charlie},只用他自己的密钥解密就可以查看他的牌了。
Manta Network 密码学开发团队用 ZKShuffle 构建了一套德州扑克 demo,这是一个基于 Solidity, React 和 Ether.js 的去中心化应用。在这个 demo 中,每当一轮新的游戏开始,所有的玩家都要进行一轮设置,以保证在链上的这幅扑克牌是公平洗过的。然后,每位玩家都需要进行一轮解密后拿到两张牌。这些,玩家就可以在一条 EVM 区块链上玩德州扑克啦。
Manta 目前已将这个 DApp 部署在了 Optimism Goerli, Ethereum Goerli 和 Skale 区块链上。
实现原理
整个项目由3部分组成:
ZK电路;
用于验证解密和洗牌的智能合约,包括ZKShuffle合约和游戏逻辑合约 DApp前端,使用React和ether.js以及Circomlib JS库构建的Demo;
Circomlib cryptographic JS库。
在Circom的实现中,采用ElGamal加密方案,并使用现有的Circom库,如poseidon hashes。
加密电路有87308个R1CS约束(constraints),在 DApp 中的证明生成时间为4.5秒。解密电路有1522个R1CS约束,在DApp中的证明生成时间为0.1秒。使用SnarkJs来生成DApp中的零知识证明。
智能合约由两部分组成:ZKShuffle 框架合约和德扑游戏逻辑合约。ZKShuffle 合约简易封装了ZKP 验证逻辑和两个电路。逻辑合约部署了一个状态机,从RPC节点获得游戏当前阶段和轮到哪个玩家的次序。
DApp 使用 React 框架和 Ether.js 实现,展示德扑桌面以及每位玩家的动作动画。当需要玩家做出动作时,这个玩家只需点击 UI 中的按钮,使用 metamask 进行交易签名即可。
观看Demo:
https://drive.google.com/drive/folders/1ymUL3jDT1CZdqMKGVVneMXz8uh0A-HYb
Twitter:https://twitter.com/MantaNetwork
Medium:https://mantanetwork.medium.co
Discord:https://discord.gg/ZtSuSKRy8X
Telegram中文:https://t.me/mantanetwork_zh
Twitter中文:https://twitter.com/manta_china