在这个教程中,我们将学习如何开发一个基于以太坊的零知识身份证明DApp, 学习如何开发Circom零知识电路、如何生成并方法Solidity零知识验证智能合约, 以及如何利用Javascript在链下生成零知识证据,并在教程最后提供完整的源代码下载。

区块链开发教程链接: 以太坊 | 比特币 | EOS | Tendermint | Hyperledger Fabric | Omni/USDT | Ripple

1、零知识身份证明DApp概述

我们将开发一个零知识应用来证明一个用户属于特定的群组 而无需透露用户的具体信息,使用流程如下图所示:

我们的开发过程分为以下几个步骤:

  • 开发零知识电路
  • 生成用于验证零知识电路的Solidity库
  • 开发智能合约并集成上述Solidity库
  • 本地生成证据并在链上进行验证

2、零知识证明以太坊DApp开发环境搭建

就像你不需要完全理解HTTP协议也可以开发web应用一样,已经有很多 工具可以帮助开发基于零知识的DApp而无需密码学或数学基础。

我推荐如下的开发语言和工具链:

  • JavaScript/TypeScript:应用采用javascript/typescript开发,因为这两者在以太坊生态中得到很好的支持
  • Solidity: 智能合约用Solidity开发,因为它很成熟并且社区很好
  • Truffle:使用Truffle作为智能合约开发和部署框架
  • Circom:使用Circom来开发零知识证明电路

3、CIRCOM零知识电路开发:判断私钥是否匹配公钥集

我们的目标是创建一个电路,该电路可以判别输入的私钥是否对应 于输入的公钥集合之一。该电路的伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
// Note that a private key is a scalar value (int)
// whereas a public key is a point in space (Tuple[int, int])
const zk_identity = (private_key, public_keys) => {// derive_public_from_private is a function that// returns a public key given a private keyderived_public_key = derive_public_from_private(private_key)for (let pk in public_keys):if derived_public_key === pk:return truereturn false
}

我们现在要开始用circom编写零知识电路了。circom的语法可以查阅 其官方文档。

首先创建项目文件夹并安装必要的依赖包:

1
2
3
4
5
6
7
npm install circom circomlib snarkjs websnarkmkdir contracts
mkdir circuits
mkdir -p build/circuitstouch circuits/circuit.circom

现在编写电路文件circuit.circom,首先引入(incluude)必要的基础电路 并定义PublicKey模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
include "../node_modules/circomlib/circuits/bitify.circom";
include "../node_modules/circomlib/circuits/escalarmulfix.circom";
include "../node_modules/circomlib/circuits/comparators.circom";template PublicKey() {// Note: private key needs to be hashed, and then pruned// to make sure its compatible with the babyJubJub curvesignal private input in;signal output out[2];component privBits = Num2Bits(253);privBits.in <== in;var BASE8 = [5299619240641551281634865583518297030282874472190772894086521144482721001553,16950150798460657717958625567821834550301663161624707787222815936182638968203];component mulFix = EscalarMulFix(253, BASE8);for (var i = 0; i < 253; i++) {mulFix.e[i] <== privBits.out[i];}out[0] <== mulFix.out[0];out[1] <== mulFix.out[1];
}

PublicKey模板的作用是在babyJubJub曲线上找出私钥(电路输入)对应的公钥(电路输出)。 注意在上面的电路中,我们将输入私钥声明为私有信号,因此在生成的证据中不会包含 任何可以重构该输入私钥的信息。

一旦完成上述的基础模块,现在就可以构建我们的零知识证明电路的主逻辑了 —— 验证 指定的用户是否属于一个群组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
include ...template PublicKey() {...
}template ZkIdentity(groupSize) {// Public Keys in the smart contract// Note: this assumes that the publicKeys// are all uniquesignal input publicKeys[groupSize][2];// Prover's private keysignal private input privateKey;// Prover's derived public keycomponent publicKey = PublicKey();publicKey.in <== privateKey;// Make sure that derived public key needs to// matche to at least one public key in the// smart contract to validate their identityvar sum = 0;// Create a component to check if two values are// equalcomponent equals[groupSize][2];for (var i = 0; i < groupSize; i++) {// Helper component to check if two// values are equal// We don't want to use ===// as that will fail immediately if// the predicate doesn't hold trueequals[i][0] = IsEqual();equals[i][1] = IsEqual();equals[i][0].in[0] <== publicKeys[i][0];equals[i][0].in[1] <== publicKey.out[0];equals[i][1].in[0] <== publicKeys[i][1];equals[i][1].in[1] <== publicKey.out[1];sum += equals[i][0].out;sum += equals[i][1].out;}// equals[i][j].out will return 1 if the values are equal// and 0 if the values are not equal// Therefore, if the derived public key (a point in space)// matches a public keys listed in the smart contract, the sum of// all the equals[i][j].out should be equal to 2sum === 2;
}// Main entry point
component main = ZkIdentity(2);

现在我们编译、设置并生成该电路的Solidity验证器:

1
2
3
4
5
6
7
8
9
10
11
$(npm bin)/circom circuits/circuit.circom -o build/circuits/circuit.json# snarkjs setup might take a few seconds
$(npm bin)/snarkjs setup --protocol groth -c build/circuits/circuit.json --pk build/circuits/provingKey.json --vk build/circuits/verifyingKey.json# Generate solidity lib to verify proof
$(npm bin)/snarkjs generateverifier --pk build/circuits/provingKey.json --vk build/circuits/verifyingKey.json -v contracts/Verifier.sol# You should now have a new "Verifier.sol" in your contracts directory
# $ ls contracts
# Migrations.sol Verifier.sol

注意我们使用groth协议生成证明密钥和验证密钥,因为我们希望使用websnark来生成证据, 因为websnark要比snarkjs性能好的多。

一旦完成上面的环节,我们就已经实现了零知识证明逻辑。下面的部分我们将 介绍如何使用生成的Solidity零知识验证合约。

4、Solidity零知识验证合约

在完成零知识电路的设置之后,会生成一个名为Verifier.sol的solidity库。如果 你查看这个文件的内容,就会看到其中包含如下的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...function verifyProof(uint[2] memory a,uint[2][2] memory b,uint[2] memory c,uint[4] memory input) public view returns (bool r) {Proof memory proof;proof.A = Pairing.G1Point(a[0], a[1]);proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);proof.C = Pairing.G1Point(c[0], c[1]);uint[] memory inputValues = new uint[](input.length);for(uint i = 0; i < input.length; i++){inputValues[i] = input[i];}if (verify(inputValues, proof) == 0) {return true;} else {return false;}}...

这是用于验证零知识证据有效性的辅助函数。verifyProof函数接收4个参数,但是 我们只关心其中表示电路公共输入的input参数,我们将使用它在智能合约代码中 验证用户的身份。让我们看一下具体的实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
pragma solidity 0.5.11;import "./Verifier.sol";contract ZkIdentity is Verifier {address public owner;uint256[2][2] public publicKeys;constructor() public {owner = msg.sender;publicKeys = [[11588997684490517626294634429607198421449322964619894214090255452938985192043,15263799208273363060537485776371352256460743310329028590780329826273136298011],[3554016859368109379302439886604355056694273932204896584100714954675075151666,17802713187051641282792755605644920157679664448965917618898436110214540390950]];}function isInGroup(uint256[2] memory a,uint256[2][2] memory b,uint256[2] memory c,uint256[4] memory input // public inputs) public view returns (bool) {if (input[0] != publicKeys[0][0] &&input[1] != publicKeys[0][1] &&input[2] != publicKeys[1][0] &&input[3] != publicKeys[1][1]) {revert("Supplied public keys do not match contracts");}return verifyProof(a, b, c, input);}
}

我们创建一个新的合约ZkIdentity.sol,它继承自生成的Verifier.sol, 有一个包含2个成员公钥的初始群组,以及一个名为isInGroup的函数,该函数 首先验证电路的公开输入信号与智能合约中的群组一致,然后返回对输入 证据的验证结果。

逻辑并不复杂,不过的确也满足了我们的目标:验证一个用户属于特定 的群组而无需透露用户是谁。

在继续下面的部分之前,需要先部署合约到链上。

5、用JavaScript生成零知识证据并与智能合约交互

一旦我们完成了零知识电路并实现了智能合约逻辑,就可以生成证据 并调用智能合约的isInGroup方法进行验证了。

下面的伪代码展示了如何生成证据并利用智能合约进行验证,你可以 访问这里 查看完整的js代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Assuming below already exists
const provingKey // provingKey.json
const circuit // zero-knowledge circuit we wrote
const zkIdentityContract // Zk-Identity contract instanceconst privateKey  // Private key that corresponds to one of the public key in the smart contract
const publicKeys = [[11588997684490517626294634429607198421449322964619894214090255452938985192043n,15263799208273363060537485776371352256460743310329028590780329826273136298011n],[3554016859368109379302439886604355056694273932204896584100714954675075151666n,17802713187051641282792755605644920157679664448965917618898436110214540390950n]
]const circuitInputs = {privateKey,publicKeys
}const witness = circuit.calculateWitness(circuitInputs)
const proof = groth16GenProof(witness, provingKey)const isInGroup = zkIdentityContract.isInGroup(proof.a,proof.b,proof.c,witness.publicSignals
)

运行js代码就可以证明你属于一个群组而无需透露你是谁!

教程的完整代码下载地址。


原文链接:A Practical Guide To Building Zero Knowledge dApps

汇智网翻译整理,转载请标明出处

零知识证明DApp开发实践【身份证明/以太坊】 | 学习软件编程

区块链 solidity 零知识证明DApp开发实践【身份证明/以太坊】相关推荐

  1. 区块链进阶-通过代币(Token)学以太坊智能合约-熊丽兵-专题视频课程

    区块链进阶-通过代币(Token)学以太坊智能合约-244人已学习 课程介绍         本课程从什么是代币(Token)讲起,分析实现一个代币关键的点是什么. 然后逐步扩展到实现标准ERC20代 ...

  2. 北京大学肖臻老师《区块链技术与应用》公开课笔记:以太坊(四):The DAO、反思、美链、总结

    10.ETH-The DAO 1).The DAO 比特币实现了去中心化的货币,以太坊实现了去中心化的合约,有人想既然去中心化这么好,为什么不把所有的东西都改成去中心化呢?有人提出口号:let's d ...

  3. 以太坊服务器是什么_OKEX区块链60讲 | 第33集:什么是以太坊?

    哈喽大家好,我是小K君,今天我们要讲的内容是:"什么是以太坊". 什么是以太坊 以太坊是数字货币中,除比特币之外,最有开创意义的一个项目,因为早期,区块链技术仅局限于数字货币,并没 ...

  4. 北京大学肖臻老师《区块链技术与应用》公开课笔记:以太坊原理(一):以太坊概述、账户、状态树、交易树和收据树

    1.ETH-以太坊概述 比特币和以太坊是两种最主要的加密货币,比特币被称为区块链1.0,以太坊被称为区块链2.0 以太坊在系统设计上针对比特币运行过程中出现的问题进行了改进,比如: 出块时间,比特币的 ...

  5. 【区块链 | 智能合约】Ethereum源代码(11)- 以太坊核心BlockChain源码分析

    前面几节都在分析以太坊的通信协议,怎么广播,怎么同步,怎么下载.这一节讲讲以太坊的核心模块BlockChain,也就是以太坊的区块链. 一,BlockChain的初始化 Ethereum服务初始化fu ...

  6. 区块链开发入门:基于以太坊智能合约构建 ICO DApp

    写给前端开发者的第一本区块链开发入门指南,通过从 0 到 1 实战开发一个 ICO DApp 项目(基于 V 神的 DAICO 设计思想),深入掌握区块链及以太坊技术. 为什么要选择区块链开发? 未来 ...

  7. 当区块链遇到零知识证明 1

    本文由云+社区发表 当区块链遇到零知识证明 什么是零知识证明 零知识证明的官方定义是能够在不向验证者任何有用的信息的情况下,使验证者相信某个论断是正确的.这个定义有点抽象,下面笔者举几个例子,来帮助读 ...

  8. 10本区块链热门图书(应用开发、智能合约等)免费送!

    欢迎访问网易云社区,了解更多网易技术产品运营经验. "互联网之后就是区块链时代,区块链是实现未来跟踪经济的关键技术."世界上真的存在 100% 去中心化的系统吗?区块链到底是什么? ...

  9. 高盛发布区块链报告:从理论到实践(中文版)

    投资组合经理之摘要 现在硅谷和华尔街都为了区块链着迷,逐渐忘记了作为其技术源头的比特币.但对其潜在应用的讨论仍十分抽象和深奥.焦点在于使用分布式账本建立去中心化市场,并削弱现有中间商的控制权. 但区块 ...

  10. 基于区块链的思考与创新应用实践

    区块链技术无疑是近两年来最热门的"金融科技"话题之一了,一度被业界认为是互联网技术之后,最有潜力触发颠覆式革命浪潮的核心技术.而中国银联自2015年起,就展开了对区块链的研究及创新 ...

最新文章

  1. 慕课python课后作业_python基础1习题练习
  2. string 转 int_面试官:String长度有限制吗?是多少?还好我看过
  3. c语言五子棋卡死,五子棋程序出错了
  4. Magento 自定义后台menu Insert dynamical menu in Magento’s Admin
  5. 前端开发工程师和美工 知识需求的区别
  6. 【转】 SQL 2005 try catch
  7. jqGrid分页点击事件,点击分页的时候滚动条回到顶端
  8. 学生评语管理系统软件测试,学校教师老师综合评价评分系统软件
  9. 装系统缺少硬盘驱动_缺少操作系统-向我学习,请在今年备份您的硬盘!
  10. 郑州园博园“私房照”曝光,8月试运营对市民免费开放!这可是咱郑州人家门口的“苏州园林”!...
  11. map集合和set集合
  12. oracle job remove,如何删除oracle Job命令实例
  13. 微信视频号头像怎么换?怎么设置?必看!5个思路帮你快速敲定头像
  14. 阿里云——云数据库RDS
  15. 关于自己学习安卓的体会
  16. android源码结构分析
  17. Unity3D新手教学,让你十二小时,从入门到掌握!(三 )
  18. 用java制作的简易倒计时器(主要可用于考试系统中考试剩余时间显示)
  19. 如何写cover letter 翻译自How to write a cover letter
  20. X-CUBE-USB-AUDIO 资料篇②——AUD_Streaming10 USB音频设备扩展应用

热门文章

  1. 11. 判断是给属性前加typeof 可以同时判断属性是否存在
  2. AWS API Gateway Swagger定义
  3. (转)DB2 db2diag.log 日志分析
  4. Python练习5-正则表达式
  5. 使用Struts2框架开发租房系统(8)
  6. Canvas坐标轴中的Y轴距离是X轴的两倍
  7. JDBC数据源(DataSource)的简单实现
  8. JVM学习笔记 -- 从一段几乎所有人代码都会犯错的代码开始
  9. 基于Monorail的系统功能模块化
  10. java饼状图获取数据集_HighChars3D饼图(从后台获取数据)