http://www.7klian.com

实践指南:构建一个零常识证明 DApp [译]

  component mulFix = EscalarMulFix(253, BASE8);
## Migrations.sol Verifier.sol
            input[0] != publicKeys[0][0] &&
  signal input publicKeys[groupSize][2];
        }

开拓的流程有以下几个步调:
                17802713187051641282792755605644920157679664448965917618898436110214540390950
    equals[i][1].in[0] <== publicKeys[i][1];
        }
  component publicKey = PublicKey();
                3554016859368109379302439886604355056694273932204896584100714954675075151666,
结论
完成上面零常识证明电路步调之后,生成了一个名为Verifier.sol的solidity代码,有一个如下的验证函数:
  component equals[groupSize][2];
开拓情况搭建及东西
            uint[2][2] memory b,
[17] 这里: https://github.com/kendricktan/hello-world-zk-dapp

            ]
// Main 进口
[3] truffle利用: https://learnblockchain.cn/docs/truffle/
[16] JavaScript代码: https://github.com/kendricktan/hello-world-zk-dapp/blob/master/packages/scripts/index.js#L97
        proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
      15263799208273363060537485776371352256460743310329028590780329826273136298011n
        } else {
include “../node_modules/circomlib/circuits/bitify.circom”;
        proof.C = Pairing.G1Point(c[0], c[1]);
  // 确保推导的公钥需要与智能合约中的至少一个公钥匹配以验证其身份
            input[1] != publicKeys[0][1] &&
问题 1:如安在电路中安详提供私钥?
留意:此博客文章假定读者对公钥加密[6]有根基的相识,以及知晓如何陈设合约[7]和在 JavaScript 中与合约交互[8]。
  privateKey,
  out[0] <== mulFix.out[0];
        publicKeys = [
[1] public-key cryptography: https://stackoverflow.com/questions/2853889/how-does-public-key-cryptography-work
    equals[i][0].in[0] <== publicKeys[i][0];
const circuit // 我们编写的零常识证明电路
]
  // 建设一个组件以查抄两个值是否相等
首先安装须要的依赖项及建设项目文件夹,零常识电路逻辑放在circuits/circuit.circom 文件:
零常识证明电路
[2] circom 及 snarkjs 利用: https://learnblockchain.cn/article/1078
  // 留意:需要对私钥举办哈希,然后对其修剪以确保其与baby JubJub曲线兼容
    if derived_public_key === pk:
const publicKeys = [
  for (var i = 0; i < groupSize; i++) {
智能合约验证
}
    sum += equals[i][1].out;
template PublicKey() {
  derived_public_key = derive_public_from_private(private_key)
include “../node_modules/circomlib/circuits/escalarmulfix.circom”;
      3554016859368109379302439886604355056694273932204896584100714954675075151666n,
在继承下面的部门之前,需要先陈设合约到链上。
  witness.publicSignals
以下是我推荐的开拓语言和东西:
  }
        if (verify(inputValues, proof) == 0) {
  signal private input in;
[15] 这里: https://github.com/kendricktan/hello-world-zk-dapp/blob/master/packages/scripts/index.js#L97
$snarkjs setup –protocol groth -r circuit.r1cs –pk build/circuits/provingKey.json –vk build/circuits/verifyingKey.json
const zkIdentityContract // Zk-Identity 合约实例
## $ ls contracts
const circuitInputs = {
    sum += equals[i][0].out;
)
        return verifyProof(a, b, c, input);
生成证明并与智能合约交互
原文:https://kndrck.co/posts/practical_guide_build_zk_dapps/

  }
PublicKey 电路模板的浸染是在baby JubJub 曲线[13]上从提供的私钥(in)导出公钥(out)(即上述伪代码中的 derive_public_from_private 函数)。
  // 因此, 假如派生的公钥(空间中的某个点)与智能合约中列出的公钥匹配,则所有equals[i][j].out的总和应便是2
已往三年中,零常识东西的成长很是迅速。此刻,您不需要高妙的暗码学常识也可开始构建零常识应用,虽然假如你相识,将在调试时有所辅佐。
## snarkjs setup might take a few seconds
    mulFix.e[i] <== privBits.out[i];
项目根目次/contracts/Verifier.sol
    ) public view returns (bool) {
const isInGroup = zkIdentityContract.isInGroup(
            uint[2] memory c,
留意:我还在下面添加了一些有关零常识电路的常见问题解答。
      17802713187051641282792755605644920157679664448965917618898436110214540390950n
            inputValues[i] = input[i];
    address public owner;
  for (var i = 0; i < 253; i++) {
                11588997684490517626294634429607198421449322964619894214090255452938985192043,
  privBits.in <== in;
const proof = groth16GenProof(witness, provingKey)
[9] Truffle: https://learnblockchain.cn/docs/truffle/getting-started/running-migrations.html
touch circuits/circuit.circom
[13] baby JubJub 曲线: https://iden3-docs.readthedocs.io/en/latest/iden3_repos/research/publications/zkproof-standards-workshop-2/baby-jubjub/baby-jubjub.html
留意,我们将privateKey的信号指定为“私有”(private)信号。因此,生成的证明将不包括任何有关“私有”信号的信息,而仅包括“民众”(public)信号的信息。
  out[1] <== mulFix.out[1];
    16950150798460657717958625567821834550301663161624707787222815936182638968203
项目根目次/circuits/circuit.circom
        uint256[2] memory c,
        owner = msg.sender;
pragma solidity 0.5.11;
      11588997684490517626294634429607198421449322964619894214090255452938985192043n,
      return true
有了基本电路之后,就可觉得零常识电路
构建主要逻辑:验证用户是否在组内:
我们将构建一个zk-dApp,以证明用户是否属于某个特定组,而无需透露用户详细是谁。

        ];
            input[3] != publicKeys[1][1]
我们开始建设基本电路 PublicKey 电路模板:
                15263799208273363060537485776371352256460743310329028590780329826273136298011
contract ZkIdentity is Verifier {
  publicKeys
// 请留意,私钥是标量值(int)
import “./Verifier.sol”;
  // 留意: 假设这些公钥都是独一的
            uint[4] memory input
            [
这篇博客文章的目标是充当一个
实践指南,以辅佐读者成立他们的第一个零常识dApp。

此 zk-dApp 的用户流程如下图:

        }
npm install circomlib  websnark
•利用JavaScript/TypeScript 开拓
DApp,,自己有富厚的生态以及对以太坊也有很是好的支持•利用Solidity 开拓智能合约,足够成熟、社区很好•利用Truffle[9] 陈设合约•利用Circom[10] 开拓零常识证明电路
  [
  proof.b,
$ circom circuits/circuit.circom –r1cs –wasm –sym
// 假定这些都已经存在了
            return true;
npm install -g circom  snarkjs 
  // 假如相等,equals[i][j].out 会返回 1,假如不等返回 0
  // derive_public_from_private 是一个用来返回私钥对应公钥的函数
component main = ZkIdentity(2);
}
    constructor() public {
  publicKey.in <== privateKey;
运行完整的JavaScript代码[16]后,你就向用户证明白你属于一个组,而没有透露该用户是谁!
留意我们利用 groth 协议生成证明密钥provingKey 和验证密钥verifyingKey,因为我们但愿利用websnark来生成证明, 因为websnark要比snarkjs机能好的多[14]。
    uint256[2][2] public publicKeys;
问题 2:用户不能提供错误的公钥列表吗?
概述
  return false
mkdir circuits
  sum === 2;
    // 我们不利用 === 因为假如不为true, 他会当即失败
            input[2] != publicKeys[1][0] &&
        ) public view returns (bool r) {
    equals[i][1] = IsEqual();
[7] 如何陈设合约: https://learnblockchain.cn/docs/truffle/getting-started/running-migrations.html
项目根目次/circuits/circuit.circom
逻辑并不巨大,可是简直满意了我们的方针:验证一个用户属于特定的群组而无需透露用户是谁。
  ]
此刻,我们将开始利用 circom[11] 编写零常识电路。有关circom语法的先容,请阅读circom教程[12]
    function isInGroup(
    5299619240641551281634865583518297030282874472190772894086521144482721001553,
  signal output out[2];
  var sum = 0;
        uint256[2] memory a,
include …
  // 公钥在智能合约中
项目根目次/contracts/ZkIdentity.sol
  for (let pk in public_keys):
  ];
}
        if (
1.编写零常识电路2.生成用于验证零常识电路的Solidity代码库3.编写智能合约逻辑,并集成步调 2生成的 Solidity 代码库4.陈设合约.5.当地生成证明,并在链长举办验证。
        ) {
mkdir contracts
}
    equals[i][1].in[1] <== publicKey.out[1];
此刻可以编译电路、举办可信配置,并生成该电路的 Solidity 验证合约:
template ZkIdentity(groupSize) {
完成上述操纵后,我们就完成零常识逻辑。在下一节(智能合约验证)中,我们将查察生成的Verifier.sol以及如何与其举办交互。
    equals[i][0].in[1] <== publicKey.out[0];
这就是辅佐验证证明的有效性。 verifyProof函数接管4个参数,可是我们只需存眷 参数input,因为它代表了民众信号(如:在<PROJECT_ROOT>/circuits/circuit.circom的 ZkIdentity 模板中非私有输入信号)。
            revert(“Supplied public keys do not match contracts”);
  // 证明者的私钥(这是一个私有的输入信号)
mkdir -p build/circuits
强调一下, 代码在这里[17].
  // 从证明者的私钥推导出的公钥
    equals[i][0] = IsEqual();
## 应该可以看到在contracts目次下生成了一个合约文件 “Verifier.sol” 
将在下面的“智能合约验证措施”部门中具体先容这一点。
由于在JS中有许多示例代码来生成证明和实例化智能合约,因此我仅演示用于生成证明的伪代码,及在智能合约验证证明。完整的代码在这里[15]找到
        uint[] memory inputValues = new uint[](input.length);
利用input参数,我们可以针对智能合约逻辑中现有的一组民众密钥举办验证,就可以办理问题 2。
        uint256[4] memory input // public inputs
就像如今不需要相识HTTP协议来举办Web开拓一样,零常识dApp开拓具有足够现代的东西,可以使不必然具有暗码学数学配景的开拓者(譬喻:我)操作零常识证明构建应用措施 。

  component privBits = Num2Bits(253);
// 而公钥是空间中的一个点(Tuple[int, int])
[4] ethers 毗连合约: https://learnblockchain.cn/docs/ethers.js/api-contract.html#id6
            uint[2] memory a,
[6] 公钥加密: https://www.cloudflare.com/learning/ssl/how-does-public-key-encryption-work/
  ],
  [
template PublicKey() {
}
[10] Circom: https://github.com/iden3/circom
  signal private input privateKey;
    }
我们的方针是建设一个电路:该电路可以鉴别输入的私钥是否对应于输入的公钥荟萃之一。
  function verifyProof(
        for(uint i = 0; i < input.length; i++){
电路中,当且仅当私钥对应于个中一个公钥(约束)时才结构证明。电路的伪代码如下:
        proof.A = Pairing.G1Point(a[0], a[1]);
include “../node_modules/circomlib/circuits/comparators.circom”;

媒介
            ],
  var BASE8 = [
        uint256[2][2] memory b,

const provingKey // provingKey.json
一旦您编写了零常识电路并编写了智能合约逻辑,接下来就是生成证明并挪用合约函数isInGroup 。
我在建设
DApp时,险些没有什么零常识证明资料可供参考,因此我想在博客文章中分享一下建设一个零常识证明 dApp的履历。
            return false;
[14] websnark要比snarkjs机能好的多: https://github.com/iden3/websnark#important-please-be-sure-you-run-your-setup-with—protocol-groth–websnark-only-generates-groth16-proofs
在我们编写网验证用户身份的逻辑后,观念将越发详细:
  proof.c,
            [
    }
const privateKey  // 与智能合约中的公钥之一相对应的私钥
在已往的几个月中,我在上操作了零常识证明(尤其是zk-SNARKs)建设了几个简朴的dApp[5]。
  …
  proof.a,
[5] 简朴的dApp: https://github.com/kendricktan/simple-zk-rollups
    }
References
## 生成 solidity 代码用来验证证明
        Proof memory proof;
我们建设了一个新的合约ZkIdentity.sol,它担任自生成的Verifier.sol, 有一个包括2个元素的公钥的初始数组,以及一个名为isInGroup的函数,该函数 首先验证电路的果真输入信号与智能合约中的数组一致,然后返回对输入证明的验证功效。
}
[12] circom教程: https://learnblockchain.cn/article/1078
[8] 在 JavaScript 中与合约交互: https://learnblockchain.cn/docs/ethers.js/api-contract.html
$snarkjs generateverifier –pk build/circuits/provingKey.json –vk build/circuits/verifyingKey.json -v contracts/Verifier.sol
const zk_identity = (private_key, public_keys) => {
const witness = circuit.calculateWitness(circuitInputs)
[11] circom: https://learnblockchain.cn/tags/circom

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。