前序博客有:
- Mina概览
- Mina的支付流程
2021年12月,由Mina基金会和Mina生态合作伙伴O(1) Labs 与 ZK Hack 联合举办了 ZK Hack zkApps Workshop 和 zkApps Bootcamp。在这2个活动中,Mina社区可学习用SnarkyJS——为TypeScript库,用于编写Mina 零知识智能合约。
相关视频介绍有:
- ZK HACK #7 - Introduction to SnarkyJS and Snapps with Mina
- Snapps Bootcamp Intro
- Snapps Bootcamp Wrap-Up
- Zero Knowledge Smart Contracts, Snapps | Mina Protocol
- Real World Use Cases that Mina Will Enable With ZK Technology | Mina Protocol
zkApps为Mina的零知识智能合约。zkApps采用链下执行和大部分链下状态模型,支持隐私计算以及隐私状态或公开状态。在链下,zkApps可执行任意复杂的计算,仅需要支付固定费用即可将结果的零知识证明发送给链上以验证该计算,而其他区块链则是在链上运行计算并采用动态gas费用模型。 zkApps采用Mina zkApp CLI以TypeScript编写。zkApps当前支持在最新版的Chrome、Firefox、Edge和Brave浏览器上运行,未来将支持Safari浏览器。
一个zkApp中包含2个部分:
- 1)一个智能合约:Mina的智能合约是以SnarkyJS编写的。
- 2)一个UI供用户交互
由于zkApps是基于零知识证明(zk-SNARKs)的,因此zkApp开发者编写的为“circuit”——基于此可派生出Prover函数和相应的Verifier函数。
-
Prover函数:会执行智能合约的自定义逻辑。Prover函数作为zkApp的一部分,运行在用户的web浏览器内。当与zkApp UI交互时,用户将输入任何数据(如,“以 y y y价格购买ABC”)作为Prover函数的输入,该Prover函数会生成一个零知识证明。
在用户的web浏览器中,需要为Prover函数所需的private输入和public输入数据:
- private输入:提供给Prover函数之后,将不再需要。
- public输入:提供给Prover函数,也需要提供给Verifier函数。对于你想保密的数据,永远不要将其作为public输入。
-
Verifier函数:验证所提供的零知识证明通过了Prover函数中定义的所有约束。无论Prover函数有多复杂,Verifier函数的验证通常很快效率很高。
当zkApp开发者编写完智能合约,运行npm run build
,会编译输出smart_contract.js
。然后,可运行Prover函数 或 生成一个Verification Key,这些在运行 或 部署智能合约时正好需要。 Prover函数运行在用户的web浏览器之内。 指定zkApp账号的Verification Key位于链上,Mina网络会使用链上的Verification Key来验证所提供的零知识证明是否能满足Prover函数中定义的所有约束。在创建zkApp账号时,需要用到Verification Key。
开发者可使用Mina zkApp CLI来将智能合约部署到Mina网络中。部署过程是发送一笔包含了Verification Key的交易到Mina链上某地址。当Mina上的该地址包含了某Verification Key时,该地址就可作为zkApp账号。常规的Mina账号可接收任何交易,而zkApp账号仅可成功接收包含了满足Verifier函数的proof的交易。任何无法通过Verifier函数验证的交易都会被Mina网络拒绝。
当你部署一个新的Mina地址时,Mina protocol将为该账号创建收取1 MINA的手续费。这与zkApps无关,可防止女巫或DOS攻击。
2.4 部署zkApp UI 开发者通常会提供UI界面供用户与智能合约交互。UI通常为开发者部署在自定义的服务器上的静态网站。推荐web服务器可提供全局CDN以保证最佳的用户体验。该网站中需要包含之前编译智能合约所生成的
smart_contract.js
文件,
为与zkApp交互,用户必须安装 Auro钱包for Google Chrome。未来将增加更多支持zkApps的钱包。
Auro为当前唯一支持zkApp交易的钱包。将zkApp部署到主机(例如mycolzkapp.com)后,用户可以与之交互:
- 1)用户访问mycoolzkapp.com。
- 2)用户与zkApp交互,输入所需的任意数据。(如,对于自动做市商,用户可指定“以 y y y价格买 x x x个ABC”).
- 3)zkApp的Prover函数根据用户输入的数据在本地生成一个零知识证明。该数据可为保密的(不想在链上可见)或 公开的(可在链上或链下存储),具体取决于开发者的设定以及特定的应用场景。此外,随proof一起,还会生成该交易所将产生的状态更新列表。(Mina将这些状态更新列表称为“events”。)
- 4)用户点击zkApp UI中的“submit to chain”,其钱包(如浏览器扩展钱包)将弹框确认是否发送该交易。钱包对包含了proof和相应所需更新的状态说明的交易 进行签名,并将签名后的交易发送的Mina链上。
- 5)当Mina网络收到该交易,将验证proof是否成功通过了zkApp账号中的Verifier函数,若proof验证通过且相应的状态变更有效,网络将接受该交易并更新相应的zkApp状态。
由于用户交互发生在其本地web浏览器内部(客户端采用JavaScript),因此可保护用户的隐私。
2.6 链上状态如何更新?链上的zkApp账号状态是如何更新的? 当web浏览器中运行Prover函数时,智能合约会输出一个proof和某些称为“events”的关联数据。这些输出会作为交易的一部分发送到zkApp地址。这些events为以JSON形式的明文描述——描述了如何更新zkApp账号的状态。
为保证这些events的整体性,这些events的hash值会作为智能合约的public输入,以保证当传输给Mina链上的Verifier函数时确保其不会被篡改。这样,Mina网络可确认proof和events的完整性,据此来更新zkApp账号的状态。
2.7 zkApp状态Mina有2种状态类型:
- 1)链上状态:在Mina链上的状态。每个zkApp账号有8个32字节的字段,每个字段具有任意存储空间,只要大小合适,在字段内可存放任何东西。如果你预计你的状态会比这个更大,或者如果你的zkApp对每个用户累积了状态,那么你会希望使用链外状态。
- 2)链下状态:存储在其它地方,如IPFS的状态。【即将支持。】对于更大的数据,可考虑在zkApp的链上空间中存储Merkle tree root,该root会指向链下存储的状态。当在用户web浏览器中运行zkApp时,可向外部存储插入状态,如IPFS。当将该交易发送到Mina链上时,若接受该zkApp交易(即该proof&sate都是有效的),则zkApp交易将更新链上存储的Merkle tree root。
Mina zkApp CLI为目前最易上手的编写zkApp智能合约工具,其可提供项目脚手架,包括SnarkyJS、测试框架(Jest)、代码自动格式化(Prettier)、linting(ES-Lint)等依赖项。
详细的编写合约流程可参看:
- How to write a zkApp?
- https://github.com/o1-labs/zkapp-cli/
在zkApps训练营中,O(1) Labs的工程师介绍了zkApps的高层架构、如何使用SanrkyJS编写智能合约,并要求开发者使用SnarkyJS编写一个游戏。
在4天的zkApps训练营中,有一些有趣的项目:
- Mina Snapp: Stir with JarOfPickles
- Sealed Bid Auction PoC with SnarkyJS
- Mina Snapp: BullsAndCows
- SNAPP DogNet
- Mina Snapp: Snapp Hangman
由Mina社区开发的zkApps合集见:
- zkApps for Mina
zkApps的测试流程为: Initial Testing (started Q4 2021) → Public QANet (targeting Q1 2022) → Testnet ‘Berkeley’ (targeting Q2 2022)
参考资料[1] Mina Protocol Product Priorities – Q1 2022 Update [2] zkApps Workshop & Bootcamp Retro [3] What are zkApps? [4] zkApps开发者文档 [5] Mina: Using Zero-Knowledge To Make Web3 Useful for Everyone