6 个版本 (2 个稳定版本)
1.2.0 | 2022 年 9 月 29 日 |
---|---|
1.0.0 | 2022 年 3 月 21 日 |
0.5.3 | 2022 年 3 月 17 日 |
#10 在 #r1cs
每月 153 次下载
在 2 个 crate 中使用 (通过 arkworks-setups)
115KB
2K SLoC
🚀 零知识 gadgets 和电路,用于保护隐私的跨链应用程序。🚀
📖 目录
目录
构建
要构建项目,请运行
./scripts/build.sh
要为 wasm 目标构建,请运行
./scripts/build-wasm.sh
要运行单元测试,请运行
./scripts/test.sh
注意:所有命令应从根目录运行。
发布到 crates.io
对于版本管理,我们使用 cargo-workspaces。我们使用以下流程
-
使用
cargo-workspaces
提升所有 crate 的版本,使用命令cargo ws version
。这将提升工作区中所有 crate 的版本,包括- arkworks/native-gadgets
- arkworks/r1cs-gadgets
- arkworks/r1cs-circuits
- arkworks/setups
- arkworks/utils
-
上一步将只更新 crate 本身,但不会更新其依赖项。例如,如果
arkworks/setups
依赖于arkworks/utils
,则依赖项版本不会更新。我们必须手动进行此操作。 -
提交所有更改。
-
使用以下命令发布 crate:
cargo ws publish --allow-branch [current_branch] --from-git
。--allow-branch
允许我们在任何分支上发布 crates。默认情况下,它只允许在master
分支上。如果您想从master
分支发布,则不需要此选项。--from-git
标志指定 crates 应以原样发布,绕过cargo ws publish
命令带来的额外版本升级。
概述
该仓库包含用于不同终端应用(如混洗器和锚)的无知识小工具和电路,这些应用可以集成到兼容的区块链和智能合约协议中。仓库分为三个主要部分
- 中间模块化小工具
- 消耗这些小工具的电路
- 小工具和电路使用的基本实用工具(如 Poseidon 哈希函数的参数)
Gadgets
您可以将小工具视为中间计算和约束系统,您可以将它们组合起来构建更完整的无知识知识证明语句。它们也可以通过简单地扩展 arkworks ConstraintSynthesizer
来直接使用。一个使用模拟计算的示例可以在 dummy circuit 中找到。
在这个仓库中,您可以找到以下小工具
Poseidon 哈希函数与 circom 实现 匹配。基于以下论文实现:[https://eprint.iacr.org/2019/458.pdf](https://eprint.iacr.org/2019/458.pdf)。
集合成员资格 - 用于以零知识方式证明某些值在集合内部。这是通过首先计算从 target
(我们要检查成员资格的值)和集合中的每个值之间的差异(表示为 diffs
)来完成的。然后我们计算目标和集合中每个元素的乘积之和。如果 diffs
中的一个值为 0(意味着它等于 target
),则乘积将为零,从而意味着 target
在集合中。
电路
在这个仓库中,您可以找到以下电路
设置 API
对于本仓库中实现电路,我们在setup
目录中设置了配置。此文件夹包含为每个电路创建证明的特定电路的配置助手,以及Poseidon、Merkle树、证明/验证密钥生成、验证器助手等助手。
arkworks/setups/[r1cs | plonk]
中的每个特定应用文件夹封装了针对该电路的零知识证明完整设置的API。目前有特定应用的以下小工具:
有关这些更大规模应用小工具的测试和实例化的信息,请参阅该目录中的test.rs文件。此仓库中的大多数测试和实现都使用Groth16证明和零知识小工具的设置。偶尔会使用Marlin zkSNARK进行中间小工具测试。但是,没有特定应用的小工具实例化使用Marlin,但欢迎通过拉取请求创建它们。
证明者
这些零知识小工具的证明者旨在供客户端或服务器应用程序使用。这些程序计算密集,需要访问随机数生成器。
验证者
这些零知识小工具的验证器旨在供客户端、服务器或区块链应用程序使用。这些验证器与WASM兼容,并可以嵌入到WASM友好的环境中,例如允许以Rust编写的智能合约的区块链。API在特定的证明系统(如Groth16)中是一致的,并且可以轻松集成到区块链运行时,例如Substrate。
电路
混合器
混音器小工具旨在部署在基于Rust的区块链协议上。动机是在链上将有Merkle树和抵押系统,用户必须存入资产以将叶子插入Merkle树。这被视为对混音器的存款
。接下来,用户可以通过实例化混音器电路,用链上的叶子填充它,在本地的辅助实用工具中提供私有和公共输入,并随后生成零知识证明来生成一个叶子在Merkle树中的成员资格的零知识证明。然后,他们可以将此证明提交到链上的验证器。这被视为对混音器的提款
。以下提供混音器电路设置、证明过程和证明验证过程的示例实例。但首先,我们讨论混音器的结构,以阐明我们的一些设计决策。
任何零知识混音器电路的实例化都需要提供所有数据以符合预期格式。这意味着必须提供特定结构的数据给证明者。这延伸到叶子的前像,如果数据不符合预期的格式或协议,则不可能生成兼容的零知识证明以供链上验证。
叶子结构
混音器叶子的结构是从基于你的电路实例的字段(BLS381或BN254)中的两个随机字段元素(秘密和nullifier)的哈希。
公共输入结构
公共输入的结构必须是以下数据的有序数组,这些数据取自Tornado Cash的设计和架构。
- Nullifier哈希
- Merkle根
- 任意输入(不包括在计算中)
这些参数作为公共输入提供给零知识证明,并旨在实现链上可定制性。
- Nullifier哈希是随机生成的nullifier的哈希。我们对其进行哈希处理,以隐藏预映像,防止提前攻击。
- Merkle根是我们证明叶子成员所在的Merkle树的根哈希。
- 对于链上加密货币混币器,我们必须提供一个用户事先决定的私有交易中继服务,以及支付该服务的费用。这些数据包含在任意输入中——通过对这些值(中继地址、费用、收款人等)进行哈希处理。
值得指出的是,所有包含在任意输入中的值都将证明绑定到这些值上。这有助于防止篡改,例如,如果用户希望在生成证明后更改收款人,将有助于防止篡改。如果提交到链上的证明的公共输入发生变化,证明将因zkSNARK的底层安全性而失败。我们利用这种设计为最终应用(链上加密货币混币器)的用户和中继提供正确的激励。
锚
Anchor协议与混币器非常相似。我们不是证明在单个Merkle树内部的成员资格,而是在多个Merkle树中的一个中证明包含。这些树可以存在于许多不同的区块链上,如果Merkle树的状态在区块链之间同步,这将使我们能够进行跨链匿名交易。以下是Anchor工作的高级概述
- 我们使用Poseidon哈希函数计算叶子承诺,传递:
secret
(私有输入)、nullifier
(私有输入)和链ID(公共输入)。 - 我们使用Poseidon哈希函数计算nullifier哈希,传递:
nullifier
(私有输入) - 我们使用计算出的叶子和路径(私有输入)计算根哈希。
- 我们使用SetGadget检查计算出的根是否在集合(公共输入)内部。
叶子结构
叶子结构类似于混币器,除了我们还在公共输入中引入了链ID。链ID确保您只能在一个链上提现,从而防止双花。因此,Anchor叶子由secret
(随机值)、nullifier
(随机值)和chain_id
组成。
公共输入结构
- 链ID
- Nullifier哈希
- Merkle根集
- 任意输入
- 链ID——确保您只在一个链上提现,并防止双花。
- Nullifier哈希与混币器中相同,但在多链环境中使用。这意味着它将注册在具有与Chain Id相同ID的链上(我们的公共输入)。
- Merkle根集是根哈希的数组。它由本地根(提现所发生的链上的根)和其他连接到本地链的链的根组成。
- 任意输入与混币器具有相同的目的。它包括:收款人、中继、费用、退款和承诺(承诺用于刷新您的叶子——这意味着在承诺值为非零时,插入新的叶子作为旧叶子的替代)。
虚拟锚
VAnchor代表可变锚点,因为它引入了可变存款金额的概念。它支持匿名合并-分割功能,允许将多个先前存款合并成多个新存款。VAnchor还支持跨链交易。以下是VAnchor工作的高级概述
- 使用输入Utxos和相应的Merkle路径,我们计算每个Utxo的根哈希。
- 我们使用SetGadget检查每个Utxo的根哈希是否是根集的成员。
- 使用输出Utxos,我们证明从传递的私有输入中创建叶子。
- 我们确保输入金额的总和加上公共金额等于输出金额的总和。
未经验收的交易输出 (UTXOs)
UTXOs代表未花费的交易输出。每个UTXO代表可以系统内使用的保护性余额。要创建新的UTXOs,必须证明对现有UTXOs的所有权,并且这些现有UTXOs的余额至少与新建的UTXOs相等。
UTXOs包含一个值,表示UTXO中包含的金额,UTXO预期被花费的链ID,以及与创建所有权和成员资格零知识证明相关的秘密数据。
UTXOs首先通过序列化其组件,然后通过在插入之前对序列化数据进行哈希处理,在链上的Merkle树中进行存入和存储。每个哈希都可以被视为对一个UTXO的承诺。要从旧UTXOs创建新的UTXOs,用户必须提交有效的零知识证明,这些证明满足关于值的一致性和在Merkle根集合中的成员资格的约束。
公共输入
- 公共金额
- 任意输入
- 每个Utxo的Nullifier哈希数组
- 每个Utxo的叶子承诺数组
- 进行交易时的链ID
- Merkle根集
- 公共金额指定存入或提款的金额。负值表示提款,正值表示存入。
- 任意输入不计入计算。
- Nullifier哈希数组与输入Utxos相关,或是我们想要花费的Utxos。
- 叶子承诺数组与输出Utxos相关,或是我们想要存入的Utxos。
- 链ID和Merkle根集合与Anchor相同
API的示例用法
混洗器 - 生成叶子承诺和零知识证明
use arkworks_setups::{
common::{Leaf, MixerProof},
r1cs::mixer::MixerR1CSProver,
Curve, MixerProver,
};
// Setting up the constants
// Default leaf in Merkle Tree
const DEFAULT_LEAF: [u8; 32] = [0u8; 32];
// Merkle tree heigth (or depth)
const TREE_HEIGHT: usize = 30;
// Setting up the types
type Bn254 = ark_bn254::Bn254;
type MixerR1CSProver_Bn254_30 = MixerR1CSProver<Bn254, TREE_HEIGHT>;
// Random leaf creating
let Leaf {
secret_bytes,
nullifier_bytes,
leaf_bytes,
nullifier_hash_bytes,
..
} = MixerR1CSProver_Bn254_30::create_random_leaf(curve, rng)?
// Or in case you want to specify you own secret and nullifier
let Leaf {
leaf_bytes,
nullifier_hash_bytes,
..
} = MixerR1CSProverBn254_30::create_leaf_with_privates(
curve,
secret_bytes,
nullifier_bytes,
)?;
// Proof generation
let MixerProof {
proof,
..
} = MixerR1CSProver_Bn254_30::create_proof(
curve,
secret_bytes,
nullifier_bytes,
leaves,
index,
recipient_bytes,
relayer_bytes,
fee_value,
refund_value,
pk_bytes,
DEFAULT_LEAF,
rng,
)?;
锚点 - 生成叶子承诺和零知识证明
use arkworks_native_gadgets::poseidon::Poseidon;
use arkworks_setups::{
common::{
setup_params,
setup_tree_and_create_path,
AnchorProof,
Leaf,
},
r1cs::anchor::AnchorR1CSProver,
AnchorProver, Curve,
};
// Setting up the constants
// Default leaf used in Merkle Tree
const DEFAULT_LEAF: [u8; 32] = [0u8; 32];
// Merkle tree depth (or height)
const TREE_DEPTH: usize = 30;
// Number of anchors (Merkle trees we are proving the membership in)
const ANCHOR_CT: usize = 2;
type Bn254 = ark_bn254::Bn254;
type AnchorR1CSProver_Bn254_30_2 = AnchorR1CSProver<
Bn254,
TREE_DEPTH,
ANCHOR_CT
>;
// Creating a leaf
let Leaf {
secret_bytes,
nullifier_bytes,
leaf_bytes,
nullifier_hash_bytes,
..
} = AnchorR1CSProver_Bn254_30_2::create_random_leaf(
curve,
chain_id,
rng
)?;
// Or in case you want to specify you own secret and nullifier
let Leaf {
leaf_bytes,
nullifier_hash_bytes,
..
} = AnchorR1CSProver_Bn254_30_2::create_leaf_with_privates(
curve,
chain_id,
secret_bytes,
nullifier_bytes,
)?;
// Creating the proof
let AnchorProof {
proof,
..
} = AnchorR1CSProver_Bn254_30_2::create_proof(
curve,
chain_id,
secret_bytes,
nullifier_bytes,
leaves,
index,
roots_raw,
recipient_bytes,
relayer_bytes,
fee_value,
refund_value,
commitment_bytes,
pk_bytes,
DEFAULT_LEAF,
rng,
)?
V锚点 - 生成UTXOs和零知识证明
use arkworks_setups::{
common::{
prove_unchecked,
setup_params,
setup_tree_and_create_path
},
r1cs::vanchor::VAnchorR1CSProver,
utxo::Utxo,
Curve, VAnchorProver,
};
// Default leaf for the Merkle Tree
const DEFAULT_LEAF: [u8; 32] = [0u8; 32];
// Merkle tree depth (or heigth)
const TREE_DEPTH: usize = 30;
// Number of anchors (Merkle trees we are proving the membership in)
const ANCHOR_CT: usize = 2;
// Number of input transactions
const NUM_INS: usize = 2;
// Number of output transactions
const NUM_OUTS: usize = 2;
type Bn254 = ark_bn254::Bn254;
type VAnchorProver_Bn254_30_2x2 = VAnchorR1CSProver<
Bn254,
TREE_DEPTH,
ANCHOR_CT,
NUM_INS,
NUM_OUTS
>;
// Input Utxo number 1
let in_utxo_1 = VAnchorProver_Bn254_30_2x2::create_random_utxo(
curve,
in_chain_id_1,
in_amount_1,
in_index_1,
rng,
)?;
// Input Utxo number 2
let in_utxo_2 = VAnchorProver_Bn254_30_2x2::create_random_utxo(
curve,
in_chain_id_2,
in_amount_2,
in_index_2,
rng,
)?;
// Output Utxo number 1
let out_utxo_1 = VAnchorProver_Bn254_30_2x2::create_random_utxo(
curve,
out_chain_id_1,
out_amount_1,
out_index_1,
rng,
)?;
// Output Utxo number 2
let out_utxo_2 = VAnchorProver_Bn254_30_2x2::create_random_utxo(
curve,
out_chain_id_2,
out_amount_2,
out_index_2,
rng,
)?;
// Making an array of Utxos
let in_utxos = [in_utxo_1, in_utxo_2];
let out_utxos = [out_utxo_1, out_utxo_2];
// Generating proof
let VAnchorProof {
proof,
..
} = VAnchorProver_Bn254_30_2x2::create_proof(
curve,
chain_id,
public_amount,
ext_data_hash,
in_root_set,
in_indices,
in_leaves,
in_utxos,
out_utxos,
pk_bytes,
DEFAULT_LEAF,
rng,
)?;
梅克尔树 - 生成稀疏梅克尔树和梅克尔路径
// NOTE: This is optional and for tests only.
// There should be an on-chain mechanism for
// storing the roots of connected anchors,
// and way of fetching them before passing them
// into the circuits
let params3 = setup_params::<Bn254Fr>(curve, 5, 3);
let poseidon3 = Poseidon::new(params3);
let (tree, path) = setup_tree_and_create_path::<
Bn254Fr,
Poseidon<Bn254Fr>,
TREE_DEPTH
>(
&poseidon3,
&leaves_f,
index,
&DEFAULT_LEAF,
)?;
let root = tree.root();
// or
let root = path.calculate_root(&leaf, &poseidon3)?
参数生成
用于sage 脚本的参数。
在智能合约中的使用
在使用链上智能合约应用程序或类似功能内部的电路之前,需要准备4件事。
- 生成的证明和验证密钥。
- 将验证密钥存储在链上存储中。
- 链上梅克尔树数据结构。
- 链上存储中使用的nullifier哈希的数据结构。
- 用于长期存储包含叶子承诺前映像的加密注释的功能。
一旦满足这些条件,我们就可以成功实现Mixer/Anchor/VAnchor应用程序。以混洗器的例子来说,事件的顺序如下
- 用户发送证明和公共输入
- Nullifier Hash
- Merkle根
- 任意数据
- 我们检查根是否与链上梅克尔树根相同。
- 我们使用链上验证密钥验证证明。
- 我们将nullifier hash注册为已使用,以防止双花攻击。
这些协议的实现示例
- 混洗器 - Substrate Pallet,Cosmos (CosmWasm智能合约)
- 锚点 - Substrate Pallet,Cosmos (CosmWasm智能合约),Ethereum (Solidity智能合约)
- V锚点 Substrate Pallet,Ethereum (Solidity智能合约)
这些协议的代理服务链接
可信设置仪式示例链接
测试
-
您可以通过运行以下命令来运行所有
arkworks/setups
测试:cargo test --features r1cs,plonk --release
-
通过指定要运行的测试名称,您可以使用以下命令运行特定测试:
cargo test setup_and_prove_2_anchors --features r1cs,plonk --release
感谢
我们感谢 arkworks 社区对零知识基础设施的开源第一方法。这里许多小工具都利用了其他仓库中的开源工具。具体来说,我们利用了 ivls 项目中的稀疏 Merkle 树数据结构,以实现增量可验证计算。没有这些,这项工作将无法完成。
感谢以下人员在学习和实现这些小工具和电路方面提供的帮助和见解
依赖项
~5.5MB
~119K SLoC