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
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 电路,分别具有高度为 20
和 32
的 Merkle 树。
入门指南
将 RLN 添加为依赖项
我们首先将 zerokit RLN 添加到我们的 Cargo.toml
[dependencies]
rln = { git = "https://github.com/vacp2p/zerokit" }
创建 RLN 对象
首先,我们需要为所选的输入 Merkle 树大小创建一个 RLN 对象。
请注意,我们需要将电路(为输入树大小构建的 rln.wasm
)、相应的证明密钥(rln_final.zkey
或 rln_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