本文详细介绍了 ZKSNARK 技术,尤其是如何进行信任设置、设计零知识电路(如乘法电路)以及使用 Groth16 和 PLONK 协议进行相关的 ZKSNARK 操作。内容涵盖了电路的编写、编译、验证,以及如何处理非二次约束的问题。最后,作者提供了使用节点js 和 snarkjs 进行证明生成和验证的详细步骤。
ZKSNARKS 是一种强大的加密工具,可实现零知识证明,这是一种在不透露任何输入或输出信息的情况下验证计算有效性的方法。ZKSNARKS 可用于创建保护隐私的应用程序,例如匿名交易、可验证计算和去中心化身份。然而,使用 ZKSNARKS 并不简单,因为这需要对基础数学和加密原语有深入的理解,以及实施它们的实际挑战。
在这篇文章中,我们将指导你掌握使用 ZKSNARKS 和加密原语的实用知识。我们将详细讨论以下主题,并向你展示它们在实践中的实现方式:
到本文结束时,你将掌握使用 ZKSNARKS 和加密原语的坚实基础,并能够将其应用于自己的项目。让我们开始吧!
受信任设置是一个过程,涉及生成用于创建和验证零知识证明的一些参数。如我们所见,零知识证明是一种加密技术,允许证明者在不透露任何关于证明或声明的信息的情况下,向验证者证明某个声明是真实的。
某些类型的零知识证明,如 zk-SNARKs,需要受信任的设置, zk-SNARKs 是非常高效且密集的证明。受信任的设置要求一些参与者创建一些随机值,使用它们生成参数,然后销毁这些值。然后,参数被发布,供任何想要创建或验证证明的人使用。然而,受信任的设置也带来了一些风险和挑战,例如:
因此,受信任的设置需要参与者和参数用户之间的高度信任和谨慎。还有一些替代受信任的设置的方法,例如 zk-STARKs,它们不需要任何设置阶段,并且更安全透明,但也不够高效且更复杂。
问题: 什么是 Powers of Tau 仪式?解释它在 zk-SNARK 应用设置中的重要性。
回答: Powers of Tau 仪式是一种受信任的设置,涉及多个参与者共同贡献随机值以创建公共参考字符串 (CRS)。CRS 是一组用于生成和验证零知识证明的参数。
Powers of Tau 仪式在 zk-SNARK 应用的设置中非常重要,因为它使得为各种计算创建高效且安全的零知识证明成为可能。例如,zk-SNARKs 可以用于增强区块链技术如 Zcash 或 ZKSync 的隐私和可扩展性。然而,Powers of Tau 仪式也给 zk-SNARK 应用带来了一些挑战和限制,例如需要对参与者和参数的信任,并且是特定于某种大小或类型的计算。
Powers of Tau 仪式的核心理念是,每个参与者生成一个随机值并用其更新 CRS。随机值随后被销毁,以确保没有人可以访问它。然后,CRS 被传递给下一个参与者,该参与者重复相同的过程。通过这种方式,每个参与者为 CRS 添加了一些随机性,使其更加安全和不可预测。然而,这也意味着每个参与者需要保密其随机值,因为如果有人知道所有随机值,他们就可以创建虚假的证明或揭露关于证明的信息。因此,Powers of Tau 仪式需要参与者和 CRS 用户之间的高度信任和谨慎。
我们将学习如何使用 Groth16 和 Plonk ZKP 协议进行受信任的设置。
为了进行这次实践体验,我们将克隆 这个 GitHub 仓库 并逐步完成。
git clone https://github.com/adrianmcli/week1
cd week1/Q2
npm install
打开文件 contracts/circuits/HellowWorld.circom
中的 Circom 文件。这是一个用于检查 c
是否等于 a
和 b
的乘积的 Circom 电路模板。
pragma circom 2.1.4;
// 这个电路模板检查 c 是否是 a 和 b 的乘积。
template Multiplier2 () {
// 信号的声明。
signal input a; // 电路的第一个输入。
signal input b; // 电路的第二个输入。
signal output c; // 电路的输出。
// 约束条件。
c <== a * b; // 确保 c 等于 a 乘以 b 的约束。
}
// 电路的主要组件,使用 Multiplier2 模板。
component main = Multiplier2();
此外,让我们打开文件 compile-HelloWorld.sh
。此文件是一个脚本,可自动运行电路的标准 ZKSNARK 操作。
##!/bin/bash
## 这个脚本用于使用 circom 和 snarkjs 创建 HelloWorld 电路
## 需要安装 circom、snarkjs 和 wget
## 还需要从 hermez 网站下载 powersOfTau28_hez_final_10.ptau 文件
## 它将生成一个 HelloWorld 电路,一个验证密钥和一个 solidity 验证器合约
## 要运行这个 ZKSNARKS 操作脚本,你的工作目录应为 /week1/Q2/
cd contracts/circuits
## 为 HelloWorld 电路创建新目录
mkdir HelloWorld
## 检查 powersOfTau28_hez_final_10.ptau 文件是否存在
if [ -f ./powersOfTau28_hez_final_10.ptau ]; then
# 如果存在,则跳过下载步骤
echo "powersOfTau28_hez_final_10.ptau 已存在,跳过。"
else
# 如果不存在,则从 hermez 网站下载
echo '下载 powersOfTau28_hez_final_10.ptau'
wget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_10.ptau
fi
## 使用 circom 编译 HelloWorld.circom 文件
echo "正在编译 HelloWorld.circom..."
## --r1cs 选项生成一个等级-1 约束系统文件
## --wasm 选项生成一个 WebAssembly 文件
## --sym 选项生成一个符号信息文件
## -o 选项指定输出目录
circom HelloWorld.circom --r1cs --wasm --sym -o HelloWorld
## 使用 snarkjs 显示生成的 r1cs 文件的一些信息
snarkjs r1cs info HelloWorld/HelloWorld.r1cs
## 启动新的 zkey 文件并使用 snarkjs 和 powersOfTau28_hez_final_10.ptau 文件进行贡献
snarkjs groth16 setup HelloWorld/HelloWorld.r1cs powersOfTau28_hez_final_10.ptau HelloWorld/circuit_0000.zkey
## --name 选项指定贡献者名称
## -v 选项启用详细模式
## -e 选项指定贡献的熵源
snarkjs zkey contribute HelloWorld/circuit_0000.zkey HelloWorld/circuit_final.zkey --name="1st Contributor Name" -v -e="random text"
## 使用 snarkjs 从最终的 zkey 文件导出验证密钥为 JSON 文件
snarkjs zkey export verificationkey HelloWorld/circuit_final.zkey HelloWorld/verification_key.json
## 使用最终的 zkey 文件和 snarkjs 生成验证证明的 solidity 合约
snarkjs zkey export solidityverifier HelloWorld/circuit_final.zkey ../HelloWorldVerifier.sol
## 返回根目录
cd ../..
让我们逐行解析这个脚本,以理解这些 ZKSNARK 操作工作流。
#!/bin/bash
告诉操作系统这是一个 bash 脚本,这是一种可以在终端中运行命令的程序。cd contracts/circuits
将当前目录更改为 contracts/circuits
,这是保存电路文件的位置。mkdir HelloWorld
在当前目录内创建一个名为 HelloWorld
的新目录。这是存储 HelloWorld 电路文件的地方。powersOfTau28_hez_final_10.ptau
是否存在于当前目录中。此文件是生成证明所需的公共参数文件。它包含一些预计算值,这些值可以加快创建证明的过程。如果文件不存在,脚本会使用 wget
命令从 hermez 网站下载它。echo "正在编译 HelloWorld.circom..."
向终端打印一条消息:“正在编译 HelloWorld.circom...”。这通知用户下一个步骤是使用 circom 编译电路文件。circom HelloWorld.circom --r1cs --wasm --sym -o HelloWorld
在文件 HelloWorld.circom
上运行 circom 编译器,该文件包含 HelloWorld 电路的代码。编译器生成三个文件:一个等级-1 约束系统文件 (.r1cs
)、一个 WebAssembly 文件 (.wasm
) 和一个符号信息文件 (.sym
)。这些文件存储在 HelloWorld
目录中,该目录由 -o
选项指定。snarkjs r1cs info HelloWorld/HelloWorld.r1cs
在 .r1cs
文件上运行 snarkjs 库,显示对该文件的一些信息,例如电路中的约束、变量和输入的数量。snarkjs groth16 setup HelloWorld/HelloWorld.r1cs powersOfTau28_hez_final_10.ptau HelloWorld/circuit_0000.zkey
在 .r1cs
文件和 .ptau
文件上运行 snarkjs 库,生成名为 circuit_0000.zkey
的新文件。该文件是一个零知识密钥文件,包含有关电路和公共参数的信息。它用于创建电路的证明和验证密钥。snarkjs zkey contribute HelloWorld/circuit_0000.zkey HelloWorld/circuit_final.zkey --name="1st Contributor Name" -v -e="random text"
在 .zkey
文件上运行 snarkjs 库,并对其进行贡献。贡献是向 .zkey
文件中添加随机性的方式,使其更加安全。贡献生成一个名为 circuit_final.zkey
的新 .zkey
文件,这是零知识密钥文件的最终版本。--name
选项指定贡献者的名称,可以是任何字符串。 -v
选项启用详细模式,打印更多关于贡献过程的细节。-e
选项指定贡献的熵源,可以是任何字符串。snarkjs zkey export verificationkey HelloWorld/circuit_final.zkey HelloWorld/verification_key.json
在最终的 .zkey
文件上运行 snarkjs 库,并从中导出一个验证密钥。验证密钥是一个 JSON 文件,包含一些验证电路证明所需的信息。它由任何想要检查证明是否有效的人使用。snarkjs zkey export solidityverifier HelloWorld/circuit_final.zkey ../HelloWorldVerifier.sol
在最终的 .zkey
文件上运行 snarkjs 库,并从中导出一个 solidity 验证合约。solidity 验证合约是一个用 solidity 编写的智能合约,可以在以太坊区块链上验证电路的证明。它使用验证密钥作为输入,并根据证明是否有效返回 true 或 false。cd ../..
将当前目录更改回运行脚本之前的目录。当你第一次运行脚本 ./scripts/compile-HelloWorld.sh
时,你可能会遇到下面的错误。这是因为我们没有对脚本进行 执行
权限。
zsh: permission denied: ./scripts/compile-HelloWorld.sh
我们可以通过以下命令给文件添加执行权限来解决此问题。
chmod +x ./scripts/compile-HelloWorld.sh
现在,重新运行脚本 ./scripts/compile-HelloWorld.sh
。我们将看到以下输出。我在输出中添加了评论,以显示不同 ZKSNARK 操作的结果。
现在,让我们解答有关受信任设置的一些基本问题。
问题 What does the circuit in HelloWorld.circom do?
回答: 在 HelloWorld.circom 中的电路执行一个简单的算术运算。它将两个输入信号作为数字相乘,结果是电路的输出信号。
问题 compile-HelloWorld.sh
的第 7-12 行下载了一个名为 powersOfTau28_hez_final_10.ptau 的文件,用于第 1 阶段的受信任设置。什么是 Powers of Tau 仪式?解释它在 zk-SNARK 应用设置中的重要性。
回答: Powers of Tau 仪式是一种 zk-SNARK 应用的受信任设置仪式。受信任设置仪式是多个参与者协作生成创建和验证证明所需的公共参数的过程。公共参数也称为公共参考字符串 (CRS)。Powers of Tau 仪式基于一个交互协议,其中每个参与者向 CRS 贡献一些随机性并保持其输入秘密。最终的 CRS 是安全的,只要至少有一个参与者是诚实的,并且不泄露其输入。这一点很重要,因为 CRS 用于确保证明的合理性和隐私。如果 CRS 被攻陷,攻击者可以创建虚假的证明或获取有关秘密输入的一些信息。
问题 compile-HelloWorld.sh
的第 24 行生成随机熵贡献作为第 2 阶段的受信任设置。第 1 阶段和第 2 阶段受信任设置仪式有什么不同?
回答: 第 1 阶段和第 2 阶段受信任设置仪式具有不同的目的和范围。第 1 阶段是一个通用仪式,可以用于任何电路。它生成一个包含有限域中固定元素的所有可能幂的大的 CRS。第 2 阶段是一个电路特定的仪式,将第 1 阶段的 CRS 适配到特定电路。它减少了 CRS 的大小并向其添加一些电路特定的信息。
在 Circom 中不允许非二次约束。但是,有一些方法可以通过使用一些技巧或技术来实现非二次约束。我们通过使用一些辅助变量将原始的非二次约束减少为一组线性或二次约束。
例如,在 Multiplier3.circom
中,我们有三个输入信号的乘法。
pragma circom 2.1.4;
// [作业] 修改下面的电路以执行三个信号的乘法
template Multiplier3 () {
// 信号的声明。
signal input a;
signal input b;
signal input c;
signal output d;
// 约束条件。
d <== a * b * c;
}
component main = Multiplier3();
如果我们编译电路 Multiplier3.circom
,我们将得到以下错误。让我们编译一下,看看我们会得到什么:
circom ./contracts/circuits/Multiplier3.circom --r1cs --wasm --sym
我们可以通过引入如下辅助变量来解决这个问题。
u <== a * b;
d <== u * c;
更新后的电路看起来如下:
pragma circom 2.1.4;
// 修改后的电路以执行三个信号的乘法
template Multiplier3 () {
// 信号的声明。
// 输入信号 a、b 和 c,它们是数字
// 输出信号 d,也是一种数字
signal input a;
signal input b;
signal input c;
signal output d;
signal u;
// 这些约束确保输出信号 d 等于三个输入信号 a、b 和 c 的乘积
u <== a * b;
d <== u * c;
}
// 主要组件实例化电路模板并对信号赋值
component main = Multiplier3();
现在,我们可以成功编译这个更新后的电路 Multiplier3.circom
。
circom ./contracts/circuits/Multiplier3.circom --r1cs --wasm --sym
我们获得了以下输出:
scripts/compile-Multiplier3-groth16.sh
中,创建一个脚本来编译 contracts/circuits/Multiplier3.circom
并创建一个根据 compile-HelloWorld.sh
模拟的验证器合约。首先,让我们更新脚本 compile-Multiplier3-groth16.sh
,以执行所有针对 Multiplier3.circom
电路的 ZKSNARK 操作。然后我们运行脚本并检查输出。
##!/bin/bash
## 这个脚本用于使用 circom 和 snarkjs 创建一个 Multiplier3 电路
## 需要安装 circom、snarkjs 和 wget
## 还需要从 hermez 网站下载 powersOfTau28_hez_final_10.ptau 文件
## 它将生成一个 Multiplier3 电路,一个验证密钥和一个 solidity 验证合约
## 要运行这个 ZKSNARKS 操作脚本,你的工作目录应为 /week1/Q2/
cd contracts/circuits
## 为 Multiplier3 电路创建新目录
mkdir Multiplier3
## 检查 powersOfTau28_hez_final_10.ptau 文件是否存在
if [ -f ./powersOfTau28_hez_final_10.ptau ]; then
# 如果存在,则跳过下载步骤
echo "powersOfTau28_hez_final_10.ptau 已存在,跳过。"
else
# 如果不存在,则从 hermez 网站下载
echo '下载 powersOfTau28_hez_final_10.ptau'
wget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_10.ptau
fi
## 使用 circom 编译 Multiplier3.circom 文件
echo "正在编译 Multiplier3.circom..."
## --r1cs 选项生成一个等级-1 约束系统文件
## --wasm 选项生成一个 WebAssembly 文件
## --sym 选项生成一个符号信息文件
## -o 选项指定输出目录
circom Multiplier3.circom --r1cs --wasm --sym -o Multiplier3
## 使用 snarkjs 显示生成的 r1cs 文件的一些信息
snarkjs r1cs info Multiplier3/Multiplier3.r1cs
## 启动新的 zkey 文件并使用 snarkjs 和 powersOfTau28_hez_final_10.ptau 文件进行贡献
snarkjs groth16 setup Multiplier3/Multiplier3.r1cs powersOfTau28_hez_final_10.ptau Multiplier3/circuit_0000.zkey
## --name 选项指定贡献者的名称
## -v 选项启用详细模式
## -e 选项指定贡献的熵源
snarkjs zkey contribute Multiplier3/circuit_0000.zkey Multiplier3/circuit_final.zkey --name="1st Contributor Name" -v -e="random text"
## 使用 snarkjs 从最终的 zkey 文件导出验证密钥为 JSON 文件
snarkjs zkey export verificationkey Multiplier3/circuit_final.zkey Multiplier3/verification_key.json
## 生成一个用于验证证明的 solidity 合约
snarkjs zkey export solidityverifier Multiplier3/circuit_final.zkey ../Multiplier3Verifier.sol
## 返回根目录
cd ../..
compile-Multiplier3-groth16.sh
。你应该遇到电路存在的 error[T3001]
。解释此错误的含义以及如何产生。当我们运行脚本 compile-Multiplier3-groth16.sh
时,会出现 error[T3001]
错误。此错误与我们之前的非二次约束 d <== a * b* c;
有关。
我们可以通过使用辅助信号如下所示来解决此问题:
u <== a * b;
d <== u * c;
Multiplier3.circom
在 Circom 的限制下执行三个输入信号的乘法。现在,脚本 compile-Multiplier3-groth16.sh
执行 ZKSNARK 操作以构建更新后的电路 Multiplier3.circom
。它还创建了 Groth16 受信任的设置、证明、见证和验证的密钥,以及 Solidity 智能合约 Multiplier3Verifier.sol
。所有这些步骤在终端中成功完成。
pragma circom 2.1.4;
// 修改电路以执行三个信号的乘法
template Multiplier3 () {
// 信号的声明。
// 输入信号 a、b 和 c,它们是数字
// 输出信号 d,也是一种数字
signal input a;
signal input b;
signal input c;
signal output d;
signal u;
// 这些约束确保输出信号 d 等于三个输入信号 a、b 和 c 的乘积
u <== a * b;
d <== a * b * c;
}
// 主要组件实例化电路模板并赋值信号
component main = Multiplier3();
在空的 scripts/compile-Multiplier3-plonk.sh
中,创建一个脚本以使用 PLONK 在 SnarkJS 中编译 circuit/Multiplier3.circom
。为构建文件和输出合约添加 _plonk
后缀以区分两组输出。
问题 如果你仅将 snarkjs groth16 setup
更改为 snarkjs plonk setup
,你将遇到错误 zkey file is not groth16
。解决此错误并回答以下问题:使用 PLONK 编译的过程与使用 Groth16 编译有什么不同?
回答 对于 PLONK,阶段 2(电路特定)贡献是没有要求的。
下面是针对 PLONK 协议构建 Multiplier3.circom
电路的脚本 compile-Multiplier3-plonk.sh
。
##!/bin/bash
## 这个脚本用于使用 circom 和 snarkjs 使用 PLONK 协议创建一个 Multiplier3 电路
## 需要安装 circom、snarkjs 和 wget
## 还需要从 hermez 网站下载 powersOfTau28_hez_final_10.ptau 文件
## 它将生成一个 Multiplier3 电路,一个验证密钥和一个 solidity 验证合约
## 要运行这个 ZKSNARKS 操作脚本,你的工作目录应为 /week1/Q2/
cd contracts/circuits
## 为 Multiplier3 电路创建新目录
mkdir Multiplier3_plonk
## 检查 powersOfTau28_hez_final_10.ptau 文件是否存在
if [ -f ./powersOfTau28_hez_final_10.ptau ]; then
# 如果存在,则跳过下载步骤
echo "powersOfTau28_hez_final_10.ptau 已存在,跳过。"
else
# 如果不存在,则从 hermez 网站下载
echo '下载 powersOfTau28_hez_final_10.ptau'
wget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_10.ptau
fi
## 使用 circom 编译 Multiplier3.circom 文件
echo "正在编译 Multiplier3.circom..."
## --r1cs 选项生成一个等级-1 约束系统文件
## --wasm 选项生成一个 WebAssembly 文件
## --sym 选项生成一个符号信息文件
## -o 选项指定输出目录
circom Multiplier3.circom --r1cs --wasm --sym -o Multiplier3_plonk
## 使用 snarkjs 显示生成的 r1cs 文件的一些信息
snarkjs r1cs info Multiplier3_plonk/Multiplier3.r1cs
## 启动新的 zkey 文件,使用 snarkjs 和 powersOfTau28_hez_final_10.ptau 文件
snarkjs plonk setup Multiplier3_plonk/Multiplier3.r1cs powersOfTau28_hez_final_10.ptau Multiplier3_plonk/circuit_final.zkey
## --name 选项指定贡献者的名称
## -v 选项启用详细模式
## -e 选项指定贡献的熵源
## snarkjs zkey contribute Multiplier3_plonk/circuit_0000.zkey Multiplier3_plonk/circuit_final.zkey --name="1st Contributor Name" -v -e="random text"
## 使用 snarkjs 从最终的 zkey 文件导出验证密钥为 JSON 文件
snarkjs zkey export verificationkey Multiplier3_plonk/circuit_final.zkey Multiplier3_plonk/verification_key.json
## 生成一个用于验证证明的 solidity 合约
snarkjs zkey export solidityverifier Multiplier3_plonk/circuit_final.zkey ../Multiplier3Verifier.sol
## 返回根目录
cd ../..
当你运行此脚本时,它将成功构建用于证明、见证、验证和 Solidity 合约的 PLONK 基于的密钥。
问题 Groth16 和 PLONK 之间的实际区别是什么?提示:比较和对比这两种协议的合约和单元测试的运行时间(见下面的下一个问题)。
回答 PLONK 的合约大小、Gas成本和验证时间均高于 GROTH16 协议。
让我们对电路进行一些测试。
在 Circom 中没有直接的方法来进行电路的单元测试,因为 circom 只是一个编译器,输出电路表示和约束。然而,你可以使用 snarkjs
或 circom-helper
等外部工具测试电路并生成证明。这些工具允许你使用 circom 语言编译、计算见证、验证证明和调试电路。
我们还可以使用 nodejs
进行单元测试,检查证明、生成见证等。
首先,让我们使用 snarkjs
做一些基本的 ZKSNARK 操作,如验证证明、计算见证等。然后我们可以使用 nodejs
对电路和验证者智能合约进行更详细的单元测试。
让我们为 HelloWorld
电路创建输入文件。
cd contracts/circuits/HelloWorld
## 创建输入文件
echo "为 HelloWorld 电路创建输入文件 HelloWorld_input.json"
echo "{\"a\": \"3\", \"b\": \"11\"}" > ./HelloWorld_input.json
现在,计算电路的见证。
## 计算见证
echo "从 HelloWorld_input.json 生成见证,使用 HelloWorld.wasm,保存到 HelloWorld_witness.wtns"
gtime -f "[PROFILE] 见证生成时间: %E" \
node HelloWorld_js/generate_witness.js HelloWorld_js/HelloWorld.wasm ./HelloWorld_input.json \
HelloWorld_js/HelloWorld_witness.wtns
然后,为我们的见证创建证明。
## 为我们的见证创建证明
echo "开始证明我们拥有见证(我们的 HelloWorld_input.json 形式为 HelloWorld_witness.wtn)"
echo "证明和公共信号保存到 HelloWorld_proof.json 和 HelloWorld_public.json"
gtime -f "[PROFILE] 证明时间: %E" \
snarkjs groth16 prove ./circuit_final.zkey HelloWorld_js/HelloWorld_witness.wtns \
HelloWorld_js/HelloWorld_proof.json \
HelloWorld_js/HelloWorld_public.json
然后,最后,验证我们的证明。
## 验证我们的证明
echo "检查 HelloWorld_public.json 的知识证明(使用 HelloWorld_verification_key.json)"
gtime -f "[PROFILE] 验证时间: %E" \
snarkjs groth16 verify ./verification_key.json \
HelloWorld_js/HelloWorld_public.json \
HelloWorld_js/HelloWorld_proof.json
让我们计算一些基准统计(不同密钥的时间和大小性能)。
## 检查客户端侧文件的大小和性能
echo "客户端侧文件输出大小:"
echo "[PROFILE]" `du -kh "HelloWorld_js/HelloWorld.wasm"`
echo "[PROFILE]" `du -kh "HelloWorld_js/HelloWorld_witness.wtns"`
我们可以将上面的步骤合并,并将它们添加到我们的 ZKSNARKS 操作工作流脚本 compile-HelloWorld.sh
中。
当我们重新运行脚本 compile-HelloWorld.sh
时,会看到我们的 HelloWorld.circom
电路的所有操作。
我们可以以类似的方式为 Multiplier3.circom
电路更新脚本,以执行 GROTH16 和 PLONK ZKSNARK 操作。
当我们运行脚本 compile-Multiplier3-groth16.sh
时,可以看到成功的验证、见证生成和测试。
当我们运行脚本 compile-Multiplier3-plonk.sh
时,可以看到成功的验证、见证生成和测试。
你可以在 repo ZKSNARKS 中找到完整代码。
- 原文链接: github.com/thogiti/thogi...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!