5 个版本 (2 个稳定版)
1.2.0 | 2022年9月29日 |
---|---|
1.0.0 | 2022年3月21日 |
0.5.3 | 2022年3月17日 |
0.5.1 | 2022年3月17日 |
0.5.0 | 2022年3月16日 |
#14 in #leaf
每月下载 179 次
用于 4 crate
49KB
961 行
🚀 零知识插件和电路,用于保护隐私的跨链应用。 🚀
📖 目录
目录
构建
要构建项目,请运行
./scripts/build.sh
要构建为 wasm 目标,请运行
./scripts/build-wasm.sh
要运行单元测试,请运行
./scripts/test.sh
注意:所有命令应在根目录下运行。
发布到 crates.io
对于版本管理,我们使用 cargo-workspaces。我们使用以下流程
-
使用
cargo-workspaces
通过命令cargo ws version
升级所有 crate 的版本。这将升级工作空间中所有 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 哈希函数的参数)
插件
您可以想象小工具是中间计算和约束系统,您可以将它们组合起来构建更完整的知识证明。它们也可以通过简单地扩展 arkworks ConstraintSynthesizer
来直接使用。一个使用虚拟计算的示例可以在 虚拟电路 中找到。
在这个仓库中,您可以找到以下小工具:
Poseidon 哈希函数与 circom 实现 匹配。根据这篇论文实现: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 兼容,并可以嵌入到诸如允许用 Rust 编写的智能合约的区块链等 WASM 友好环境中。API 在特定的证明系统(如 Groth16)中保持一致,并且易于集成到区块链运行时(如 Substrate)中。
电路
混洗器
混合器设备旨在部署在基于 Rust 的区块链协议上。动机是在链上将有 Merkle 树和提存系统,用户必须存入资产才能将叶子插入 Merkle 树。这被视为对混合器的 存入。接下来,用户可以通过实例化一个混合器电路,用链上的叶子填充它,在本地的辅助工具中提供私有和公共输入,然后生成零知识证明,将此证明提交到链上验证器。这被视为从混合器的 提现。下面提供了一个混合器电路设置、证明过程和证明验证过程的示例实现。但首先,我们简要说明混合器的结构,以便阐明我们的设计决策。
零知识混合器电路的任何实例化都需要提供的数据格式符合预期。这意味着必须提供特定结构的数据给证明者。这延伸到叶子的预像,如果数据不符合预期的格式或协议,则无法为这些证明生成兼容的零知识证明以供链上验证。
叶子结构
混合器叶子的结构是基于您的电路实例化的字段(BLS381 或 BN254)中两个随机字段元素(秘密和nullifier)的哈希。
公共输入结构
公共输入的结构必须是以下数据的有序数组,这些数据来自 Tornado Cash 的设计和架构。
- Nullifier 哈希
- Merkle 根
- 任意输入(不包括在计算中)
这些参数作为公共输入提供给零知识证明,并针对链上可定制性进行了优化。
- 失效哈希是随机生成的失效值的哈希。我们对其进行哈希处理,以隐藏预映像,从而防止抢先攻击。
- Merkle根是我们正在证明叶子成员关系的Merkle树的根哈希。
- 对于链上加密货币混合机,我们必须提供用户事先决定的私有交易中继服务,并支付该服务的费用。这些数据包含在任意输入中——通过对这些值(中继地址、费用、收款人等)进行哈希处理。
值得指出的是,所有包含在任意输入中的值都将证明绑定到这些值上。这有助于防止篡改,例如,如果用户想在证明生成后更改收款人。如果提交到链上的证明的公共输入发生变化,则证明将因zkSNARK的底层安全性而失败。我们利用这种设计为端应用的用户和中继提供适当的激励,即链上加密货币混合机。
锚
锚定协议与混合机非常相似。我们不是在一个Merkle树内部进行成员证明,而是在多个Merkle树中进行包含证明。这些树可以存在于多个不同的区块链上,如果Merkle树的状态在不同链之间同步,这将使我们能够进行跨链匿名交易。锚定协议的高级概述
- 我们使用Poseidon哈希函数计算叶子承诺,传入:
secret
(私有输入)、nullifier
(私有输入)和链ID(公共输入)。 - 我们使用Poseidon哈希函数计算失效哈希,传入:
nullifier
(私有输入) - 我们使用计算的叶子和路径(私有输入)计算根哈希。
- 我们使用SetGadget检查计算的根是否包含在集合中(公共输入)。
叶子结构
叶子结构与混合机相似,但我们还引入了链ID作为公共输入。链ID确保你只能在一条链上提取,从而防止双花。因此,锚定叶子由secret
(随机值)、nullifier
(随机值)和chain_id
组成。
公共输入结构
- 链ID
- Nullifier 哈希
- Merkle根集
- 任意输入
- 链ID - 确保你只能在一条链上提取,从而防止双花。
- 失效哈希与混合机中的相同,但在多链环境中使用。这意味着它将注册在具有相同ID的链上(我们的公共输入)。
- Merkle根集是根哈希的数组。它由本地根(提取链上的根)和其他链的根组成,这些链与本地链相连。
- 任意输入与混合机的目的相同。它包括:收款人、中继、费用、退款和承诺(承诺用于刷新你的叶子——这意味着如果你将新的叶子作为旧叶子的替换插入,则承诺的值为非零)。
VAnchor
VAnchor是可变锚点的缩写,因为它引入了可变存款金额的概念。它支持匿名合并-拆分功能,允许将多个先前存款合并成多个新存款。VAnchor还支持跨链交易。VAnchor的高级概述
- 使用输入Utxos和相应的Merkle路径,我们计算每个Utxo的根哈希。
- 我们使用SetGadget检查每个Utxo的根哈希是否是根集的成员。
- 我们通过传递私有输入证明叶子的创建。
- 我们确保输入金额总和加上公共金额等于输出金额总和。
UTXOs
UTXO代表未花费的交易输出。每个UTXO代表可以在该系统中使用的屏蔽余额。要创建新的UTXO,必须证明对现有UTXO的所有权,这些UTXO的余额至少与新生成的UTXO一样多。
UTXOs包含一个值,表示UTXO中包含的金额、预期支出UTXO的链ID以及与创建所有权和成员资格零知识证明相关的秘密数据。
UTXOs首先通过序列化其组件,然后在对序列化数据进行哈希后插入到链上的Merkle树中进行存储。每个哈希都可以视为对一个UTXO的承诺。要从旧UTXOs创建新的UTXOs,用户必须提交有效的零知识证明,这些证明满足围绕值的一致性和一组Merkle根中的成员资格约束。
公共输入
- 公共金额
- 任意输入
- 每个Utxo的Nullifier哈希数组
- 每个Utxo的叶子承诺数组
- 交易发生的链ID
- Merkle根集
- 公共金额指定了存款或取款的金额。负值表示取款,正值表示存款。
- 任意输入不计入计算。
- Nullifier哈希数组与输入Utxos相关,或是我们想要支出的Utxos
- 叶子承诺数组与输出Utxos相关,或是我们想要存入的Utxos
- 链ID和Merkle根集与锚点中的相同
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,
)?
虚拟锚点 - 生成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,
)?;
Merkle树 - 生成稀疏Merkle树和Merkle路径
// 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件事情。
- 生成的证明和验证密钥。
- 将验证密钥存储在链上存储中。
- 链上Merkle树数据结构。
- 用于链上存储中使用的Nullifier哈希的数据结构。
- 用于长期存储包含叶子承诺预像的加密笔记的功能。
一旦满足这些条件,我们就可以成功实现Mixer/Anchor/VAnchor应用程序。以Mixer为例,事件的顺序如下
- 用户发送证明和公共输入
- Nullifier哈希
- Merkle 根
- 任意数据
- 检查根是否与链上Merkle根相同。
- 使用链上验证密钥验证证明。
- 将nullifier哈希注册为已使用,以防止双重支出攻击。
这些协议实现的示例
- 混洗器 - Substrate Pallet、Cosmos (CosmWasm智能合约)
- 锚点 - Substrate Pallet、Cosmos (CosmWasm智能合约)、Ethereum (Solidity智能合约)
- 虚拟锚点 Substrate Pallet、Ethereum (Solidity智能合约)
这些协议的中继服务链接
可信设置仪式示例链接
测试
-
您可以通过运行命令
cargo test --features r1cs,plonk --release
来运行所有arkworks/setups
测试。 -
您可以通过指定要运行的测试名称来运行特定的测试,使用以下命令:
cargo test setup_and_prove_2_anchors --features r1cs,plonk --release
感谢
我们感谢arkworks社区在零知识基础设施方面的开源第一方法。这里许多小工具利用了其他仓库中找到的开源工具。具体来说,我们从ivls项目在增量可验证计算中利用稀疏Merkle树数据结构。没有这个,这项工作将无法完成。
非常感谢以下人员在学习和实现这些小工具和电路方面的帮助和洞察
依赖项
~5.5MB
~120K SLoC