38个版本

0.4.20 2022年2月15日
0.4.18 2022年1月19日
0.4.10 2021年12月30日
0.4.0 2021年11月30日
0.3.3 2021年7月31日

#41 in 神奇豆

Download history 224/week @ 2024-03-03 229/week @ 2024-03-10 98/week @ 2024-03-17 67/week @ 2024-03-24 68/week @ 2024-03-31 17/week @ 2024-04-07 34/week @ 2024-04-14 32/week @ 2024-04-21 20/week @ 2024-04-28 22/week @ 2024-05-05 20/week @ 2024-05-12 24/week @ 2024-05-19 18/week @ 2024-05-26 26/week @ 2024-06-02 12/week @ 2024-06-09 20/week @ 2024-06-16

81 每月下载量
8 个crate(3 个直接) 中使用

MIT/Apache

575KB
10K SLoC

🚀 零知识小工具和电路,用于保护隐私的跨链应用。 🚀

GitHub Workflow Status License Apache 2.0 Twitter Telegram Discord

📖 目录

目录

构建

要构建项目,请运行

./scripts/build.sh

要为wasm目标构建,请运行

./scripts/build-wasm.sh

要运行单元测试,请运行

./scripts/test.sh

注意:所有命令都应该在根目录下运行。

发布到crates.io

对于版本管理,我们使用 cargo-workspaces。我们使用以下流程

  1. 使用 cargo-workspaces 通过命令 cargo ws version 提高所有crate的版本。这将提高工作空间中所有crate的版本,包括

    • arkworks/native-gadgets
    • arkworks/r1cs-gadgets
    • arkworks/r1cs-circuits
    • arkworks/setups
    • arkworks/utils
  2. 上一步只会更新 crate 自身,但不会更新其依赖项。例如,如果 arkworks/setups 依赖于 arkworks/utils,依赖项版本将不会更新。我们必须手动完成此操作。

  3. 提交所有更改。

  4. 使用以下命令发布 crate:cargo ws publish --allow-branch [current_branch] --from-git

    --allow-branch 允许我们在任何分支上发布 crate。默认情况下,它只能在 master 上使用。如果您希望从 master 发布,则不需要此选项。

    --from-git 标志指定 crate 应按原样发布,绕过 cargo ws publish 命令带来的额外版本升级。

概述

此仓库包含针对不同端应用的零知识小工具和电路,例如混合器和锚点,这些混合器和锚点可以集成到兼容的区块链和智能合约协议中。仓库分为三个主要部分:

  • 中间模块化小工具
  • 消耗这些小工具的电路
  • 小工具和电路使用的基本实用工具(如 Poseidon 哈希函数的参数)

小工具

您可以将小工具视为中间计算和约束系统,您可以将它们组合起来构建更完整的零知识知识证明语句。它们也可以通过扩展 arkworks ConstraintSynthesizer 简单地使用。一个使用模拟计算的示例可以在 dummy circuit 中找到。

在此仓库中,您将找到以下小工具:

Poseidon 哈希函数与 circom 实现 相匹配。基于以下论文实现:https://eprint.iacr.org/2019/458.pdf

集合成员资格 - 用于以零知识方式证明某个值是否在集合内。这是通过首先计算从 target(我们要检查成员资格的值)到集合中每个值的差值(记为 diffs)来完成的。然后我们计算目标和集合中每个元素乘积的总和。如果 diffs 中的某个值为 0(意味着它等于 target),则乘积将为零,这意味着 target 在集合中。

电路

在此仓库中,您将找到以下电路:

设置API

对于本仓库中实现的电路,我们在设置目录中有设置。这个文件夹包含了创建每个电路的证明所需的具体设置助手,以及用于Poseidon、默克尔树、生成/验证密钥生成、验证器助手等。

arkworks/setups/[r1cs | plonk]中的每个特定应用的文件夹封装了该电路零知识证明完整设置的API。目前有针对以下应用的特定应用小工具:

  • 混合器:R1CS、PLONK(待定)
  • 锚点:R1CS、PLONK(待定)
  • 虚拟锚点:R1CS、PLONK(待定)

有关这些更大规模应用小工具的测试和实例化,请参阅该目录中的test.rs文件。本仓库中的大多数测试和实现都使用Groth16证明和设置进行零知识小工具。偶尔也会使用Marlin zkSNARKs进行中间小工具测试。但是,没有使用Marlin进行特定应用实例化的小工具,但欢迎提交pull请求来创建它们。

证明者

这些零知识小工具的验证器旨在由客户端或服务器应用程序使用。这些验证器计算密集,需要访问随机数生成器。

验证者

这些零知识小工具的验证器旨在由客户端、服务器或区块链应用程序使用。这些验证器与WASM兼容,并可以嵌入到WASM友好的环境中,如允许用Rust编写的智能合约的区块链。API与特定的证明系统(如Groth16)一致,并易于集成到区块链运行时,如Substrate

电路

混合器

混合器小工具是为了在基于Rust的区块链协议上部署而构建的。动机是在链上有一个默克尔树和托管系统,用户必须存入资产才能将叶插入到默克尔树中。这被视为对混合器的存入。接下来,用户可以通过实例化混合器电路,在链上填充叶,在本地向实用程序提供私有和公共输入,然后生成零知识证明来证明叶在默克尔树中的成员资格。然后,他们可以将此证明提交到链上的验证器。这被认为是混合器的提现。下面提供混合器电路设置、证明过程和验证过程的一个示例。

任何零知识混合器电路的实例化都需要提供的数据都按照预期的格式进行格式化。这意味着必须提供特定结构的数据,这延伸到叶的预像,如果数据不符合预期的格式或协议,则无法为这些证明生成兼容的零知识证明,以便进行链上验证。

叶结构

混合器叶的结构是基于您电路的实例化,从字段(BLS381或BN254)中哈希了2个随机域元素(秘密和nullifier)。

公共输入结构

公共输入的结构必须是以下数据的有序数组,这些数据取自Tornado Cash的设计和架构。

  1. Nullifier哈希
  2. Merkle根
  3. 任意输入(不计入计算)

这些参数作为公共输入提供给零知识证明,并针对链上可定制性进行了优化。

  • Nullifier哈希是随机生成的nullifier的哈希。我们对其进行了哈希处理,以隐藏预像,防止抢跑攻击。
  • Merkle根是我们证明叶子成员资格的Merkle树的根哈希。
  • 对于链上加密货币混币器,我们必须提供用户预先决定的私有交易中继服务,并支付该服务的费用。这些数据包含在任意输入中——通过对这些值(中继地址、费用、收款人等)进行哈希处理。

值得一提的是,所有包含在任意输入中的值都将证明与这些值绑定。这有助于防止篡改,例如,如果用户想在证明生成后更改收款人。如果链上提交的证明的公共输入发生变化,则证明将因zkSNARK的底层安全性而失败。我们利用这种设计为最终应用——链上加密货币混币器的用户和中继者提供适当的激励。

Anchor协议与混币器非常相似。我们不是在一个Merkle树内部进行成员资格证明,而是在多个Merkle树中的一个进行包含证明。这些树可以存在于多个不同的区块链上,如果Merkle树状态在链间同步,这将允许我们进行跨链匿名交易。关于Anchor如何工作的更高层次概述

  1. 我们使用Poseidon哈希函数计算叶子承诺,传递:secret(私有输入)、nullifier(私有输入)和链ID(公共输入)。
  2. 我们使用Poseidon哈希函数计算nullifier哈希,传递:nullifier(私有输入)
  3. 我们使用计算出的叶子和路径(私有输入)计算根哈希
  4. 我们使用SetGadget检查计算出的根是否在集合(公共输入)内部

叶结构

叶子结构与混币器类似,只不过我们还在公共输入中引入了链ID。链ID确保您只能在一条链上提现,从而防止双重花费。因此,Anchor叶子由一个secret(随机值)、nullifier(随机值)和一个chain_id组成。

公共输入结构

  1. 链ID
  2. Nullifier哈希
  3. Merkle根集合
  4. 任意输入
  • 链ID确保您只能在一条链上提现,从而防止双重花费。
  • Nullifier哈希与混币器中相同,只不过它用于多链环境中。这意味着它将注册在具有相同ID的链上(我们的公共输入)。
  • Merkle根集合是一个根哈希数组。它包括本地根(提现链上的根)和其他与本地链相连的链的根。
  • 任意输入与混币器的用途相同。它包括:收款人、中继者、费用、退款和承诺(承诺用于刷新您的叶子——这意味着如果承诺的值为非零,则插入新的叶子作为旧叶子的替代)。

V锚

VAnchor简称为可变锚点,因为它引入了可变存款金额的概念。它支持匿名联合-分裂功能,允许将多个以前的存款合并成多个新的存款。VAnchor还支持跨链交易。关于VAnchor如何工作的更高层次概述

  1. 使用输入Utxos和相应的Merkle路径,我们计算每个Utxo的根哈希。
  2. 我们使用SetGadget检查每个Utxo的根哈希是否是根集合的成员。我们这样做。
  3. 使用输出Utxos,我们证明了从之前私有输入创建叶子节点。
  4. 我们确保输入金额总和加上公共金额等于输出金额总和。

UTXOs

UTXOs代表未使用的交易输出。每个UTXO代表可以在系统中使用的受保护余额。要创建新的UTXOs,必须证明对现有UTXOs的所有权,这些现有UTXOs的余额至少与新创建的UTXOs相等。

UTXOs包含一个值,表示UTXO中包含的金额,UTXO打算使用的链ID,以及与创建所有权和成员资格零知识证明相关的秘密数据。

UTXOs首先通过序列化其组件,然后通过在插入之前对序列化数据进行散列,存储在链上Merkle树中。每个散列都可以被视为对一个UTXO的承诺。要从旧UTXOs创建新的UTXOs,用户必须提交有效的零知识证明,这些证明满足围绕值的一致性和Merkle根集中成员资格的约束。

公共输入

  1. 公共金额
  2. 任意输入
  3. 每个Utxo的Nullifier散列数组
  4. 每个Utxo的叶子承诺数组
  5. 交易执行的链ID
  6. 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,
)?

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,
)?;

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件事情。

  1. 生成的证明和验证密钥。
  2. 将验证密钥存储在链上存储中。
  3. 链上Merkle树数据结构。
  4. 用于链上存储中使用的nullifier散列的数据结构。
  5. 用于长期存储包含叶子承诺预像的加密笔记的功能。

一旦满足这些条件,我们就可以成功实现Mixer/Anchor/VAnchor应用程序。在混合器的例子中,事件顺序如下

  1. 用户发送证明和公共输入
    • Nullifier散列
    • Merkle根
    • 任意数据
  2. 我们检查根是否与链上Merkle根相同。
  3. 我们使用链上验证密钥验证证明。
  4. 我们将nullifier散列注册为已使用,以防止双重花费攻击。

这些协议实现的示例

这些协议的中间人服务的链接

可信设置仪式示例的链接

测试

  • 您可以通过运行以下命令来运行所有 arkworks/setups 测试:cargo test --features r1cs,plonk --release

  • 您可以通过指定要运行的测试名称来运行特定测试,命令如下:cargo test setup_and_prove_2_anchors --features r1cs,plonk --release

感谢

我们感谢arkworks社区在零知识基础设施方面的开源第一方法。这里的一些小工具利用了其他仓库中的开源工具。具体来说,我们从ivls项目利用稀疏Merkle树数据结构进行增量可验证计算。没有这些,这项工作将无法完成。

感谢以下人员在学习和实施这些小工具和电路方面提供的帮助和见解

依赖关系

~8MB
~155K SLoC