#zk-snarks #proof #zk-proofs #verify #system #merkle-tree #zero-knowledge-proofs

rln

APIs 用于管理、计算和验证 zkSNARK 证明和 RLN 原语

15 个不稳定版本 (3 个重大更改)

0.5.1 2024 年 6 月 20 日
0.4.3 2024 年 4 月 8 日
0.4.2 2024 年 3 月 7 日
0.4.1 2023 年 10 月 4 日
0.3.0 2023 年 7 月 31 日

#7 in #zk-proofs

MIT/Apache

4.5MB
3.5K SLoC

Zerokit RLN 模块

本模块提供了管理、计算和验证 RLN zkSNARK 证明和 RLN 原语的 API。

先决条件

安装依赖项并克隆仓库

make installdeps
git clone https://github.com/vacp2p/zerokit.git
cd zerokit/rln

构建和测试

在模块文件夹内运行以下命令进行构建和测试

cargo make build
cargo make test

编译 ZK 电路

包含 RLN 电路实现的 rln (https://github.com/rate-limiting-nullifier/circom-rln) 仓库是 Zerokit RLN 的子模块。

编译 RLN 电路

# Update submodules
git submodule update --init --recursive

# Install rln dependencies
cd vendor/rln/ && npm install

# Build circuits
./scripts/build-circuits.sh rln

# Copy over assets
cp build/zkeyFiles/rln-final.zkey ../../resources/tree_height_15
cp build/zkeyFiles/rln.wasm ../../resources/tree_height_15

注意,上述代码片段将根据在 vendor/rln/circuit/rln.circom 中设置的默认值编译一个高度为 15 的 Merkle 树的 RLN 电路。

为了编译一个具有高度 N 的 RLN 电路,只需将 vendor/rln/circuit/rln.circom 改为

pragma circom 2.0.0;

include "./rln-base.circom";

component main {public [x, epoch, rln_identifier ]} = RLN(N);

但是,如果 N 太大,这可能需要比在 ./scripts/build-circuits.sh 中硬编码的更大的 Power of Tau 祭祀,该祭祀为 2^14。在这种情况下,我们参考官方的 Circom 文档,了解如何运行适当的 Power of Tau 祭祀和 Phase 2,以便编译所需的电路。

目前,rln 模块附带 2 个预编译的 RLN 电路,分别具有高度为 2032 的 Merkle 树。

入门指南

将 RLN 添加为依赖项

我们首先将 zerokit RLN 添加到我们的 Cargo.toml

[dependencies]
rln = { git = "https://github.com/vacp2p/zerokit" }

创建 RLN 对象

首先,我们需要为所选的输入 Merkle 树大小创建一个 RLN 对象。

请注意,我们需要将电路(为输入树大小构建的 rln.wasm)、相应的证明密钥(rln_final.zkeyrln_final.arkzkey)和验证密钥(可选的 verification_key.arkvkey)的位置传递给 RLN 对象构造函数。

在以下内容中,我们将使用 cursors 作为与 RLN 公共 API 交互的读取器/写入器。

use rln::protocol::*;
use rln::public::*;
use std::io::Cursor;

// We set the RLN parameters:
// - the tree height;
// - the tree config, if it is not defined, the default value will be set
let tree_height = 20;
let input = Cursor::new(json!({}).to_string());

// We create a new RLN instance
let mut rln = RLN::new(tree_height, input);

生成身份密钥对

我们生成一个身份密钥对

// We generate an identity pair
let mut buffer = Cursor::new(Vec::<u8>::new());
rln.key_gen(&mut buffer).unwrap();

// We deserialize the keygen output to obtain
// the identity_secret and id_commitment
let (identity_secret_hash, id_commitment) = deserialize_identity_pair(buffer.into_inner());

将利率承诺添加到 RLN Merkle 树

// We define the tree index where id_commitment will be added
let id_index = 10;
let user_message_limit = 10;

// We serialize id_commitment and pass it to set_leaf
let rate_commitment = poseidon_hash(&[id_commitment, user_message_limit]);
let mut buffer = Cursor::new(serialize_field_element(rate_commitment));
rln.set_leaf(id_index, &mut buffer).unwrap();

请注意,当树叶子没有由用户明确设置时(在本例中,所有索引小于 10 或大于 10 的叶子),它们的值将被设置为硬编码的默认值(在当前实现中为全 0 字节)。

设置外部 nullifier

external nullifier 包含两个参数。

第一个是 epoch,它用于识别在一定时间框架内接收到的消息。它通常对应于当前的 UNIX 时间,但也可以设置为随机值或由种子生成,只要它对应于域元素即可。

第二个是 rln_identifier,它用于防止为一个应用程序生成的 RLN ZK 证明被用于另一个应用程序。

// We generate epoch from a date seed and we ensure is
// mapped to a field element by hashing-to-field its content
let epoch = hash_to_field(b"Today at noon, this year");
// We generate rln_identifier from a date seed and we ensure is
// mapped to a field element by hashing-to-field its content
let rln_identifier = hash_to_field(b"test-rln-identifier");

let external_nullifier = poseidon_hash(&[epoch, rln_identifier]);

设置信号

信号是我们正在计算 RLN 证明的消息。

// We set our signal
let signal = b"RLN is awesome";

生成 RLN 证明

我们为证明生成例程准备输入。

输入缓冲区序列化为 [ identity_key | id_index | external_nullifier | user_message_limit | message_id | signal_len | signal ]

// We prepare input to the proof generation routine
let proof_input = prepare_prove_input(identity_secret_hash, id_index, external_nullifier, signal);

我们现在可以生成一个 RLN ZK 证明,以及 ZK 电路评估的 公共输出


// We generate a RLN proof for proof_input
let mut in_buffer = Cursor::new(proof_input);
let mut out_buffer = Cursor::new(Vec::<u8>::new());
rln.generate_rln_proof(&mut in_buffer, &mut out_buffer)
    .unwrap();

// We get the public outputs returned by the circuit evaluation
let proof_data = out_buffer.into_inner();

字节向量 proof_data 序列化为 [ zk-proof | tree_root | external_nullifier | share_x | share_y | nullifier ]

验证 RLN 证明

我们为证明验证例程准备输入。

输入缓冲区序列化为 [proof_data | signal_len | signal ],其中 proof_data 是(计算得到的)通过 generate_rln_proof 获得的输出。

// We prepare input to the proof verification routine
let verify_data = prepare_verify_input(proof_data, signal);

// We verify the zk-proof against the provided proof values
let mut in_buffer = Cursor::new(verify_data);
let verified = rln.verify(&mut in_buffer).unwrap();

我们检查证明验证是否成功

// We ensure the proof is valid
assert!(verified);

参与其中!

Zerokit RLN 公共和 FFI API 允许与比上面简要展示的更多功能进行交互。

我们邀请您通过运行来检查我们的 API 文档

cargo doc --no-deps

并查看单元测试以了解如何接口和使用它们。

依赖项

约 26-39MB
约 524K SLoC