# 在 Starknet 上隐私验证 zk-SNARK：零知识的低成本魔法

By [Starknet 中文](https://paragraph.com/@starknet-zh) · 2024-12-05

---

> _原文：_[_Zero-Knowledge Magic for Cheap_](https://medium.com/@tekkac/zero-knowledge-magic-on-starknet-56ac2453234f)_  
> 翻译及校对：_[_Starknet 中文社区_](https://twitter.com/StarkNet_ZH)_  
> 📑 转载请注明出处 🕹️_

* * *

> _你来到了俱乐部，但忘带了身份证，安保人员们正盯着你看。_
> 
> _如果你能在不透露太多信息的情况下证明自己的年龄就好了。_
> 
> _这正是零知识证明的作用所在。_

精选速览
====

*   现在，你可以通过 Starknet 来验证 zk-SNARK 了。
    
*   Starknet 是发布零知识证明的最经济的方式¹。
    
*   _赚取收益_？这个「消息」由本文独家提供。
    

* * *

零知识入门包 🎒
=========

我们需要三种关键成分。

[**Starknet**](https://x.com/CairoLang/status/1846539307651137956) 就像一条超级强大的高速公路，复杂的智能合约可以在这里以低成本的价格快速运行。你们可以把 Starknet 看作是以太坊的一个速度飞快的「亲戚」。

[**Circom²**](https://docs.circom.io/) 是你所在社区的证明生成器。它允许开发者编写程序，[隐藏部分输入信息](https://docs.circom.io/)。

[**Garaga**](https://github.com/keep-starknet-strange/garaga) 是 Starknet 的证明检查器。就像一个非常精密的安保人员，能够直接在 Starknet 上_验证数学证明_。

* * *

整个过程是如何协同工作的 🔄
===============

首先，我们需要用一种支持零知识证明的编程语言**编写**我们想要检查的**计算**。这类语言允许指定**私密输入**，并能够编译成我们所称之为 zk 电路的形式。

![](https://storage.googleapis.com/papyrus_images/ef48609ab1235cd245c4560d116107167f09185be21487e295b45684a517465a.png)

作为黑匣子的 ZK 电路

接下来，我们需要选择一个**框架**来生成和验证证明，具体取决于你是只需要本地验证，还是希望**将证明发布**到链上，供所有人查看。

整个流程如下：

1.  🧑‍💻 **编写代码**并编译你的 zk 电路
    
2.  🧮 **证明**：生成一个证明
    
3.  🏗️ 在链上**部署**验证器
    
4.  ✅ **验证**：在链上发布并验证证明
    

**如果你想保持神秘感，请不要继续往下读**。🙈

* * *

一步一步来 (Cairo) ✨
===============

第一步：创建你的电路
----------

    pragma circom 2.0.7;
    
    include "../../node_modules/circomlib/circuits/comparators.circom";
    include "../../node_modules/circomlib/circuits/poseidon.circom";
    
    template Auth() {
        signal input password;
        signal input hash;
        signal output out;
    
        component hasher = Poseidon(1);
        hasher.inputs[0] <== password;
    
        // Add the hash to output for testing
        out <== hasher.out;
    
        component eq = IsEqual();
        eq.in[0] <== hasher.out;
        eq.in[1] <== hash;
    
        1 === eq.out;
    }
    
    component main {public [hash]}= Auth();
    

这个 Circom 程序通过将密码与其 Poseidon 哈希值进行比对来验证某人是否知道密码。

**额外加分**：尝试在 [zkrepl.dev](https://zkrepl.dev/) 上实现，点击[此处生成 Poseidon 哈希值](https://poseidon-hash.online/)。

编译完成后，你将获得一个**私有证明密钥**和一个**验证密钥**。

现在，给定一个私密**输入**，

    {
      "password": "0x476172616761526f636b73",
      "hash": "137293068078....58724960716461"
    }
    

你可以使用**证明密钥_在你的机器_**上生成一个证明：

*   格式为 groth16 的证明文件 `proof.json`
    
*   文件中包含的所有公共输入 `public.json`
    

**技术细节**：\*也可使用 zkrepl.dev 生成证明。此外，你还可以[通过 Git 复制此仓库](https://github.com/tekkac/circom_test)，使用 \*`snarkjs` _框架在本地生成证明。_

现在，零知识魔法确保了两件事：

1.  **任何人都可以验证**这个证明，并确信你知道密码
    
2.  **任何人都无法**通过查看该证明**得知密码⁴**。
    

第二步：使用 Garaga 编写验证器
-------------------

现在我们已经有了 `proof.json`，让我们在 Starknet 上部署一个验证器，发布证明供所有人查看。

1\. 首先，Garaga 可以自动生成一个适用于你电路的 Starknet 验证器合约。我们只需要与编译电路绑定的验证密钥：

    garaga gen --system groth16 -vk verification_key.json
    

2\. 声明验证器，暂时无需部署，你可以使用：

    starkli declare target/dev/verifier.contract_class.json
    

3\. 使用合约中的验证器来处理证明。

    fn verify_login(proof: Span<felt252>) {
      // Get the caller 
      let caller = get_contract_address();
      // Get the verifier implementation
      let class_hash = self.verifier_class.read();
      let garaga_verifier = IVerifierLibraryDispatcher { class_hash };
    
      // Check the proof
      let result = garaga_verifier.verify_groth16_proof_bn254(proof);
      assert!(result.is_some(), "invalid proof");
    
      let expected_hash = *result.unwrap()[0];
      assert(self.hash.read(caller) == expected_hash, "Wrong authentication")
    }
    

4\. 使用 [Garaga CLI](https://garaga.gitbook.io/garaga/deploy-your-snark-verifier-on-starknet/groth16/generating-calldata-from-a-proof-and-using-your-deployed-contract/using-python-garaga-cli) 发布证明，生成交易数据并通过 starkli 发送交易。

    garaga calldata --system groth16 \ 
                    --vk verification_key.json \ 
                    --proof proof.json \ 
                    --public-inputs public.json
    

* * *

等一下？！🫴
=======

我们并没有解决最初的「我已经超过21岁了」这个问题，对吧？

确实如此，但我们证明了两件事：

1.  零知识应用的难点在于编写验证电路。
    
2.  一切皆有可能。你可以使用 [OpenPassport](https://docs.openpassport.app/docs/technical-docs/circuits) 私密地访问公民的出生日期，或者直接使用它们的 API 来创建证明，免去繁琐步骤。
    

Starknet 的费用和 Garaga 的先进优化技术使得这一切的成本变得很低。

费用表如下：

*   部署：约 5 美元
    
*   链上证明验证：小于 1 美元
    

* * *

来挑战吗，兄弟？🤺
==========

_准备好练习了吗？证明你的能力并获得奖励。_

**通过将你的 Starknet 地址的因式分解 ZK 证明发送到这个合约，证明你能够分解整数：**[**挑战合约**](https://voyager.online/contract/0x016c2c5ec9585a958a6c99be1169e202eec67fdd5b130e29533b53a7eebb600e)

**_你必须提供一组包含 32 个整数的列表，这些整数相乘等于你的地址。_**

> _例如，如果你的地址是 0x31337，即十进制的 201527，_
> 
> _可能的因子包括 1、137、1471、201527。_
> 
> _一个有效的输入示例是：\[201527, 1, 1, 1, 1, …, 1\]（31 个 1）_

因子越多，得分和**奖励**就越高。

1 的因子不算在内，请将你的输入格式化为一个包含 32 个整数的数组。

查看 [zk-mint 仓库](https://github.com/tekkac/zk-mint)，获取更多关于如何生成和发布证明的线索。

如果你成功解决了，记得来 [https://x .com/tek\_kac](https://x.com/tek_kac) 发推分享哦 :)

* * *

**脚注：**

\[¹\] 这里的「最便宜的」的意思是指，这是据我所知，请不要引用我这句话。

\[²\] 我们使用 Circom，但其他 zk-DSL³ 也能通过 Garaga 处理：如 Gnark 或 Risc0。

\[³\] zk-DSL：零知识领域特定语言。

\[⁴\] 相信我，现在数学证明不适合放在这个脚注里。

---

*Originally published on [Starknet 中文](https://paragraph.com/@starknet-zh/starknet-zk-snark)*
