本文将讨论ZK如何可能成为增加SBT用户数据隐私的关键技术以及如何项目应用零知识灵魂绑定代币。
原文标题:The Construction of the Soul Part 3: Soulbound Token with zk-SNARK Implementation
原文作者:Spartan Labs
原文来源:Medium
编译:DAOrayaki
SBT 可以更好的帮助用户验证某个属性,但极易泄漏隐私。使用零知识证明技术来保证用户数据的安全可能是一个重要的选择。
在这篇文章中,我们将讨论ZK如何可能成为增加SBT用户数据隐私的关键技术以及如何项目应用零知识灵魂绑定代币。
1.什么是零知识证明
2.ZK 证明如何与 SBT 一起使用?
3.什么是zk-SNARK?
4.ZKSBT 工作原理的解释
4.1.1 生成随机 Lambda
4.1.2 生成证明密钥和验证密钥
4.1.3 证明和验证密钥的共享
4.1.4 证明的生成
4.1.5 用户属性验证
5.高级示例
5.1 链上与链下算法
6.zkSBT 的实现
6.1 电路创建
6.2 设置阶段
6.2.1 密钥生成
6.3 证明生成阶段
6.4 验证程序阶段
6.4.1 项目如何在其 SBT 中使用 Verifier.sol?
6.4.1.1 风险:防止重放攻击
6.5 实现架构
7.ZKSBT(zk-SNARK SBT)与Counter Party Soul的可组合性
7.1 单一方法:SBT 发行人承担责任
7.2 多重方法:每个项目都承担责任
8. 结论
零知识证明允许一方(证明者)向另一方(验证者)证明一个陈述是真实的,而不会透露任何超出陈述本身有效性的信息。
证明者必须让验证者相信他拥有满足某种关系的秘密参数(称为证人)的知识,而不向验证者或其他任何人透露该证人。
项目可以通过使用ZK证明来验证灵魂的属性(例如,它具有某些成员资格)。还可以通过允许用户验证任意的断言,而不需要给出除声明本身之外的任何进一步信息。
例如,在一个政府文件和其他证明可以加密证明的世界里,有人可以证明这样一个声明:"我是新加坡公民,年满18岁,拥有计算机科学的大学学位,还没有在这个系统中申请账户。"
还有其他 ZK 技术;然而,zk-SNARKs 是在 Dark Forest Eth、Tornado cash 和 ZK-Rollups 等应用中使用的最突出的 ZK 技术。
zk-SNARK 是 ZK-proof 技术的一种实现,它代表零知识简洁、非交互式知识论证。
首字母缩略词的各个部分具有以下含义:
简单地说,这基本上意味着证明是一个数据的集合,可以在没有证明者参与的情况下独立验证。
举例来说,SBT 的用户是证明者,向用户发放 SBT 的项目方是验证者。
假设一个项目正在查看用户是否具有某个属性“secret_attribute”。用户必须证明他们有属性 `secret_attribute` 而不会泄露他们的秘密 `s`,它用于将属性 `secret_attribute` 散列到 `hash_attribute`。
通常情况下,用户会通过向项目提供秘密`s`来证明这一点,之后项目可以计算出哈希`hash_attribute`。然而,在zk-SNARK中,用户可以只提交他们拥有属性`secret_attribute`的证明,而不透露他们的秘密`s`。
我们可以用下面的程序C来描述用户的情况。
换句话说:该程序接受一个公共哈希值`hash_attribute`和一个秘密值`secret_attribute`,如果`secret_attribute`的SHA-256哈希值等于`hash_attribute`,则返回true。
使用函数`C(hash_attribute,secret_attribute)`,用户需要创建他们拥有`secret_attribute`的证明,而不需要透露`secret_attribute`。这就是zk-SNARKs解决的一般问题。
为了实现这个证明和验证系统,该项目首先要进行以下操作。
生成 lambda 是证明的第一步。记下生成器的秘密参数 lambda。任何了解此参数的人都可以在不知道秘密“w”的情况下创建评估为真的假证明。
因此,运行生成器需要一种非常安全的方法,以确保没有人在任何地方发现和存储参数。这就是 Zcash 团队在确保参数 lambda 在此过程中被销毁的同时生成证明密钥和验证密钥的极其复杂的仪式的基本原理。
该项目必须生成两个公开的密钥--证明密钥`pk`,和验证密钥`vk`。密钥生成程序G需要一个秘密参数`lambda`和一个程序`C`。这些密钥是公共参数,只需要为一个给定的程序C生成一次。
在大多数情况下,这个程序C是以电路的形式实现的(更多细节在下一节)。
用程序C和lambda生成证明密钥`pk`和验证密钥`vk`。
一个独立于用户和项目的受信任的独立小组可以运行生成器,并以一种没有人知道lambda的方式创建证明密钥`pk`和验证密钥`vk`。
然后,任何信任相关各方的人都可以在未来的互动中使用这些密钥。
该项目将与用户共享证明密钥`pk`和验证密钥`vk`。然后,这些密钥可以用来生成基于用户属性的证明,以及验证属性。
这里的 "共享 "一词用得很宽泛。项目不需要明确披露,但他们可以在前端提供一个功能,允许用户或交易方进行自己的证明或验证。
项目为用户生成证明和验证密钥
然后,用户需要证明他知道散列到已知散列“hash_attribute”的“secret_attribute”。为此,用户使用输入 pk、H 和 s 运行证明算法“generate_proof”来创建证明“prf”:
H 是 s 使用 SHA256 的公共哈希。
其中 H 是哈希密钥,s 是密钥,pk 是证明密钥
用户生成证明
当项目要检查用户是否具有某个属性时
用户将生成的证明“prf”提供给运行验证函数“verify(vk, H, prf)”的项目。
该项目计算 `verify(vk, hash_attribute, prf)`,如果证明正确则返回 true,否则返回 false。
该验证算法也可以在链上。
如果验证算法返回 true,则项目可以确信用户具有该属性,但用户不需要向验证项目透露其属性。
一个zk-SNARK由三个算法`G`、`P`、`V`组成,定义如下。
生成器程序(Generator )
密钥生成器 "G "接受一个秘密参数 "lambda "和一个程序 "C "来产生两个公开可用的密钥,一个证明密钥 "pk "和一个验证密钥 "vk"。这些钥匙是公共参数,对某个程序'C'可以只生成一次。
通过对lambda的适当处置,生成算法可以脱离链路。然后,生成的证明密钥和验证密钥可以与用户共享。
请注意,程序C也被称为公共算术电路。
证明者程序(Prover )
证明者P接受证明密钥 "pk"、公共输入 "x "和私人见证 "w "作为输入。该算法生成一个证明`prf = P(pk, x, w)`。
用户的证明生成可以通过证明和验证密钥及其证人在链外完成。建议在链下生成证明,因为生成证明的计算成本很高,而且用户的秘密可能在链上被泄露。
证人是由用户的秘密转换而来,这对我们的约束来说是一个有效的解决方案。
验证者程序(Verifier)
验证者 V 计算“V(vk, x, prf)”,如果证明正确则返回 true,否则返回 false。因此,如果证明者知道证人 `w` 满足`C(x,w) == true`,则此函数返回 true。
验证可以在链上完成,因为它相对较小,需要输入证明、秘密的哈希值和验证密钥作为公共输入参数。
链下
链上
zk-SNARKs的全部可信设置过程
我们已经通过一个高级示例来说明 zk-SNARKs 和 SBT 如何协同工作。在本节中,我们将通过一个简单的示例来说明项目如何实施 zk-SNARK 和 SBT 以使交易对手能够验证灵魂的属性。
假设信用借贷平台为用户铸造了一个 SBT,并为用户分配了信用评分。
信用借贷平台希望允许其他交易对手的项目来验证用户评分是否高于某个阈值。
我们怎么能创造这个?
此应用程序有 4 个不同的部分。前端、后端、智能合约和电路。电路是与 zk 证明的生成和验证相关的主要组件,因此我们将更多地关注这一点。
在我们可以使用 zk-SNARK 之前,我们首先必须将我们的程序规范转换为电路。对于电路的创建,我们使用的是 IDEN3 团队设计的 circom2 库。该库已用于许多其他流行的应用程序,例如 Tornado Cash 和游戏 Darkforest Eth。
例如,电路设计旨在允许用户铸造具有信用评分但没有其他人知道信用评分是什么样的 SBT。然而,用户仍然可以证明他的信用评分高于阈值并且他是值得信赖的。
简单来说,我们将设计一个简单的电路,如果用户的分数高于公共阈值,则返回 true,而无需用户透露他的分数。
https://github.com/SpartanLabsXyz/zk-sbt/blob/master/circuits/demo/circuits.circom
在我们的资源库中,我们还包括了其他针对不同使用情况的电路实例。项目可以考虑不同的电路,以满足其特定的限制。
https://github.com/SpartanLabsXyz/zk-sbt/tree/master/demo/circuits
电路设计注意事项
zk-SNARKs 更难的部分是实施适当的电路约束以确保程序执行。如果电路没有正确实现,它可能会被利用,并且由于程序的零知识性质,很难检测到这种利用。
什么是电路?
电路是指确定我们的约束的程序。
zk-SNARKs 不能直接应用于任何计算问题。问题首先需要转换为正确的形式。第一步是将程序转换为代数电路。
有关更多信息,请查看他们的文档
https://docs.circom.io/background/background/#zero-knowledge-proofs
A - B > 0,其中A是用户的秘密,而B是我们在验证算法中使用的阈值。
首先,信用贷款平台首先生成一个随机λ。在我们的例子中,我们使用tau的权力,这是一个多方仪式的可信设置,以分散的方式生成随机λ。
请注意,存在不同的复杂过程来生成这个随机 lambda,这是至关重要,通过保持未知,以防止任何人伪造证明。
对于我们的应用程序,我们创建了一个示例脚本 `execute.sh` 来运行设置过程。
6.2.1、 密钥生成
为了创建和检查证明,我们使用了一个名为 SnarkJS 的库,由 Jordi Baylina 和 Iden3 构建。SnarkJS 使用您的电路在 JavaScript 和 Solidity 中生成证明和验证代码,以及协议参数、证明和验证密钥。
证明密钥和验证密钥示例:
https://github.com/SpartanLabsXyz/zk-sbt/tree/master/circuits/demo
“证明”是用户为了证明自己的属性而生成的。
但是,在用户的输入属性可以用作证明之前,必须先将其转换为见证。
使用 circom2 库,我们可以通过命令轻松生成见证
`节点生成_见证。
js 电路.wasm ../input.json 见证.wtns`
其中 input.json 是用户的输入,也就是用户的信用评分。
证明的生成可以在客户端的链下完成,它接受程序(在电路中)的输入、见证人和证明密钥。使用带有 Groth16 协议的 snarkjs,我们可以使用
`snarkjs groth16 证明电路_0001.zkey witness.wtns proof.json public.json`
Groth16 是 zkSNARK 证明方案的具体实现。在这里阅读更多。
一旦我们生成了证明,我们就可以继续由用户验证证明。
对于验证,我们是在链上进行的。使用`snarkjs`库,用户可以从提供的验证密钥中生成验证算法。然后,验证算法可用于使用`snarkjs`库生成一个solidity智能合约
在生成 `Verification.sol` 后,我们可以使用函数 `verifyProof` 来证明给定的 SBT 具有有效属性。
本质上,`verifyProof` 是一个接受哈希和证明并返回布尔值的函数。
合约:https://github.com/SpartanLabsXyz/zk-sbt/blob/master/contracts/Verifier.sol
6.4.1 、项目如何在其 SBT 中使用Verifier.sol?
项目可以在 SBT 合约中包含验证者作为接口,如函数 `validateAttribute` 所示。
这允许任何项目包含链上验证机制,其中所有用户需要的只是他们的证明,以及验证其属性的验证密钥。
https://github.com/SpartanLabsXyz/zk-sbt/blob/master/contracts/zkSBT.sol
验证属性
函数中的输入`a,b,c,inputs`是snarkjs generate call函数生成的参数。
`@param _soul` 是灵魂的地址。`@param verifierAddress` 是为 Verifier.sol 合约部署的地址。如果证明有效,该函数返回 true,否则返回 false
6.4.1.1 、风险:防止重放攻击
验证算法的风险之一是攻击者如何能够提交另一个用户的证明作为他们自己的证明并因此得到验证。项目必须注意这可能是可能的。一些解决方案正在添加检查或无效符,以防止攻击者提交其他用户的证明。
简而言之,带有 Circom 和 Snarkjs 实现的 zk-SNARKs 可以用下面的实现来概括。
用户可以在本地创建证明,然后上传简短的证明以在智能合约中进行恒定时间验证,计算成本很高。
整体架构可以在我们的资源库中查看:
https://github.com/SpartanLabsXyz/zk-sbt#architecture
有关集成 zk-SNARK 的步骤的更多信息,您可以参考我们的 GitHub,或者更具体地说,是用于生成所有算法和证明的脚本 `execute.sh`。
https://github.com/SpartanLabsXyz/zk-sbt/blob/master/circuits/execute.sh
在我们的示例中,我们将发行 SBT 的项目的角色与可能想要验证灵魂属性的交易对手结合起来。但是,对于 SBT 与其他可能想要验证用户 SBT 属性的交易对手项目的可组合性,我们必须根据所使用的方法进行一些更改。
在 SBT 中的数据简单明了的情况下,SBT 发行者可能希望生成自己的 lambda、证明密钥和验证密钥。然后,他们可以提供一个界面,允许交易对手项目验证用户的属性。
优点是这允许轻松采用 SBT,因为其他项目可以利用现有的验证机制,而无需生成和存储自己的 lambda。
但是,如果 SBT 中的数据不同,并且存在几个旨在证明 SBT 不同属性的不同程序 C,这可能不可行。
单个交易对手项目将负责生成 lambda、证明密钥和验证密钥,而不是 SBT 发行者或中心化机构。然后,密钥和验证方法将通过项目的应用程序分发给用户。
但是,SBT 发行人应提供包含特征的 SBT 数据结构的清晰文档,同时保持数据的私密性。
这种策略可能适合不想为保护其秘密承担全部责任的 SBT 发行人。此外,如果需要 SBT 中的多个数据证明,则可能需要多个验证程序,每个程序都有自己的证明和验证密钥。
此外,该策略消除了对中央机构的依赖,而是将确保证明有效性的责任置于项目本身。
然而,这种策略需要每个项目根据被测试的属性开发自己的生成、证明和验证算法。
总之,这篇文章是关于如何使用 zk 技术使 SBT 真正私有化以及项目如何在solidity 中实现 zkSBT 的入门读物。
SBT 允许将社会身份与去信任的可组合性相结合,如果做得好,可能会改变 web3 生态系统的未来。信任和所有权的核心方面可以上链,以增强智能合约世界中的社会可组合性,这可以为去中心化应用程序打开许多可能性。
未来的一个重要研究方向是对不同种类的数据权限的确切限制进行界定,对保持数据隐私的具体技术组合进行研究,以及对可以建立在SBTs之上的产品进行研究,以创造一个 “匿名经济"。
责任编辑:Kate