本文是零知识证明简单实践教程的第三部分,
第一部分见:零知识证明第一部分,
第二部分见:零知识证明第二部分。

下面这个图片是我们在第二部分所使用的merkle树来构造prover的承诺。同时我们也提出这样的方式存在verifier暴力破解获取叶子节点明文信息的风险,特别是在明文信息所在的数据域(or集合)有限且很小的情况下。我们希望,verifier只能知道prover向他揭露的叶子节点的信息,其他的叶子节点的信息无法知道。为了解决这个问题,我们增加随机的叶子节点。

下面图片表示的是我们增加随机的叶子节点。现在,如果要向verifier发送一个证明Sir是树的一个叶子节点的验证路径,需要向他发送4,10,11,3号节点。对于4号节点,因为它是Yes节点和随机数一起作用的hash,所以verifier是无法通过暴力的方式来找到hash值和明文信息的关联关系的。

那么将上一篇中的这一部分的代码改进之后变为:

class ZkMerkleTree:"""A Zero Knowledge Merkle tree implementation using SHA256"""def __init__(self, data):self.data = datanext_pow_of_2 = int(2**ceil(log2(len(data))))self.data.extend([0] * (next_pow_of_2 - len(data)))# Intertwine with randomness to obtain zero knowledge.rand_list = [random.randint(0, 1 << 32) for x in self.data]self.data = [x for tup in zip(self.data, rand_list) for x in tup]# Create bottom level of the tree (i.e. leaves).self.tree = ["" for x in self.data] + \[hash_string(str(x)) for x in self.data]for i in range(len(self.data) - 1, 0, -1):self.tree[i] = hash_string(self.tree[i * 2] + self.tree[i * 2 + 1])def get_root(self):return self.tree[1]def get_val_and_path(self, id):# Because of the zk padding, the data is now at id * 2id = id * 2val = self.data[id]auth_path = []id = id + len(self.data)while id > 1:auth_path += [self.tree[id ^ 1]]id = id // 2return val, auth_pathdef verify_zk_merkle_path(root, data_size, value_id, value, path):cur = hash_string(str(value))# Due to zk padding, data_size needs to be multiplied by 2, as does the value_idtree_node_id = value_id * 2 + int(2**ceil(log2(data_size * 2)))for sibling in path:assert tree_node_id > 1if tree_node_id % 2 == 0:cur = hash_string(cur + sibling)else:cur = hash_string(sibling + cur)tree_node_id = tree_node_id // 2assert tree_node_id == 1return root == cur

小结

现在我们的零知识证明协议过程为:

  1. prover生成见证witness,也即是数组p。(使用第一部分文章的get_witness函数)。
  2. prover根据p来生成一个merkle树,p的各个元素都保存在叶子节点,并将根节点发送给verifier。
  3. verifier发送一个随机整数 i 给prover
  4. 如果 i < n,prover向verifier发送
    • p的下标为i和i+1的元素
    • 上面两个元素所对应的merkle树的验证路径。
  5. 如果 i==n,prover向verifier发送p的第一个和最后一个元素的值,以及对应的merkle树的验证路径。
  6. verifier验证merkle树的验证路径是否一致,如果一致,进一步验证这两个p的元素是否符合数组p的那两个特性(第一部分文章讲到)。
  7. verifier返回True或者False。

上面的步骤只是零知识证明的一个回合,在这个回合中,prover有可能根本就没有符合条件的数组m,它发给verifier的p的元素可能碰巧符合了验证条件。毕竟prover只向verifier揭露了p中两个元素的值。因此,为了打破“碰巧”,上面的过程需要进行很多次,如果每一次都通过,那么verifier就能够以很高的概率相信prover确实拥有符合条件的数组m。具体地,这个概率怎么算呢?

假设数组p的所有元素中只有一个元素是不正确的,那么一次验证不通过的概率为
1n+1\frac{1}{n+1}n+11​

其中n表示数组p的长度,因为每次暴露p的两个元素,所以分母是n+1。如果重复验证k次,那么一次验证不通过的概率是(也即是prover被逮到的概念)

1−(1−1n+1)k1 - (1 - \frac{1}{n+1})^k 1−(1−n+11​)k

设置k = 100(n+1),prover被逮到的概念是
1−1e1001 - \frac{1}{e^{100}} 1−e1001​
这个值非常接近于1,可以说是prover被逮到的概念基本为1.

因此,只要我们重复多次验证过程,若都通过,就能够有很大很大的概率认为prover确实拥有符合条件的m。

另一个问题

现在的验证过程存在一个很大的问题,那就是需要prover和verifier多次在线交互交换信息。在实际的应用中这是很不实用的。

通过上面的验证过程,我们发现prover和verifier之间的信息交互最重要的一环是verifier向prover发送随机数 i。之所以需要由verifier发送 i 给prover,是因为我们需要保证 i 是随机生成的。那么,如果我们能够保证 i 的生成是足够随机的,或者说我们所有的人都觉得这个 i 的生成方式的随机的,不管由谁来生成,这都无所谓了。现在我们假设prover生成足够随机的数 i。prover进行如下模拟过程:

  • prover模拟verifier那边的所有操作,通过一个seed来生成一个随机数 i 。(seed跟python的random函数参数seed是一个概念。)
  • prover模拟了由 i 所指定的p中的两个元素和merkle树的验证路径,以及承诺,并把这些数据保存起来。
  • 上面模拟步骤重复了预定好的次数之后,将这些模拟过程中的数据作为证明发送给verifier。

verifier根据所收到的证明重复prover的模拟过程。如果模拟通过,表示验证通过。

上面的过程感觉是prover自问自答,然后告诉verifier它是可信的。

但是,实际上,也是关键点是,随机数 i 生成的种子seed是需要特殊处理的,下面是它的处理步骤:

  1. 在prover模拟第一个验证的时候,它将数组m作为hash函数的输入,输出值作为种子seed。
  2. 在prover模拟第二次验证的时候,它将第一个验证所生成的证明作为hash函数的输入,输出值作为种子seed。
  3. 上面过程重复,直到生成最后的证明。

我们发现,上面的seed的生成过程是可以复现的,除了第一个。我们根据hash函数的特性,比如SHA256函数,基本不可能找到同一个hash值所对应的两个不同的输入值。而且,将hash值作为随机数的种子,我们觉得是足够随机的。这里的“足够”我们没有严格的定义,只是一种主观上的理解。

基于上面的随机数 i 生成的随机性,我们就有理由相信prover的自问自答是能够接受的。因此,我们就解决了prover和verifier需要同时在线,需要多次交互信息的问题。现在,只需要prover生成一个证明,其他一个或者多个verifier就能够验证了。

上面便是零知识证明的整个过程。下面是代码部分,其他部分代码请看第一部分和第二部分的文章。

def get_proof(problem, assignment, num_queries):proof = []randomness_seed = problem[:]for i in range(num_queries):witness = get_witness(problem, assignment)tree = ZkMerkleTree(witness)random.seed(str(randomness_seed))query_idx = random.randint(0, len(problem))query_and_response = [tree.get_root()]query_and_response += [query_idx]query_and_response += tree.get_val_and_path(query_idx)query_and_response += tree.get_val_and_path((query_idx + 1) % len(witness))proof += [query_and_response]randomness_seed += [query_and_response]return proofdef verify_proof(problem, proof):proof_checks_out = Truerandomness_seed = problem[:]for query in proof:random.seed(str(randomness_seed))query_idx = random.randint(0, len(problem))merkle_root = query[0]proof_checks_out &= query_idx == query[1]# Test witness properties.if query_idx < len(problem):proof_checks_out &= abs(query[2] - query[4]) == abs(problem[query_idx])else:proof_checks_out &= query[2] == query[4]# Authenticate pathsproof_checks_out &= \verify_zk_merkle_path(merkle_root, len(problem) + 1, query_idx, query[2], query[3])proof_checks_out &= \verify_zk_merkle_path(merkle_root, len(problem) + 1, \(query_idx + 1) % (len(problem) + 1), query[4], query[5])randomness_seed += [query]return proof_checks_out

测试

def test(q):problem = [1, 2, 3, 6, 6, 6, 12]assignment = [1, 1, 1, -1, -1, -1, 1]proof = get_proof(problem, assignment, q)print(proof)return verify_proof(problem, proof)

第一部分教程:https://blog.csdn.net/liangyihuai/article/details/105421598
第二部分教程:https://blog.csdn.net/liangyihuai/article/details/105430792

转载请注明出处

零知识证明实践教程,第三部分相关推荐

  1. 零知识证明实践教程,第一部分

    本文和其他博客文章的区别: 现今存在很多讲解零知识证明的文章,但是它们都是只涉及到很浅层的概念理解和直观感受上面,没有深入到零知识证明的细节,导致读者只知道什么是零知识证明,而不清楚怎么构造一个零知识 ...

  2. 零知识证明实践教程,第二部分

    本文是零知识证明简单实践教程的第二部分, 第一部分见:零知识证明第一部分 第三部分见:零知识证明第三部分 现在一个问题是,prover(证明者)可能撒谎,比如原本它应该向verifier(验证者)揭露 ...

  3. linux编程课后作业,Unix/Linux 编程实践教程第三章习题

    tips: 答案仅供参考,不保证正确* 3.1 在我的 deepin 上,d_name 的长度是 256,有的系统定义成 1 是为了节省空间,使用时可以通过 malloc() 动态的分配空间,比如: ...

  4. UNIX-LINUX编程实践教程-第三章-实例代码注解-ls2

    一 问题 对ls1的功能进行扩展,以达到类似ll命令的功能. 二 分析 在ls1中,我们利用readdir()函数和dirent结构体来获得目标文件夹内的文件名(dirent->d_name). ...

  5. Symfony3.0 实践教程 (三) 安装与配置Symfony

    安装与配置Symfony 原文 http://symfony.com/doc/current/book/inst... 通过 Composer 来创建一个 Symfony 应用 安装好 compose ...

  6. 【密码学】Python用零知识证明实现地图三染色问题

    题目:用零知识证明实现地图的三染色问题(用三种颜色染色一个地图,保证任意两个相邻的地区都是不同的颜色). 编程验证下述的设计思路,采用Python和C语言编写均可. 条件:假设一个交互协议有证明者Al ...

  7. 【区块链基础知识系列】 第8课 区块链之零知识证明

    所谓零知识证明,指的是示证者在证明自己身份时不泄露任何信息,验证者得不到示证者的任何私有信息,但又能有效证明对方身份的一种方法. 从本质上讲,零知识证明是一种协议.所谓协议(Protocol),就是两 ...

  8. 零知识证明学习资源汇总

    本文将继续会持续进行更新,更新后的版本将在 Github 和知乎上发布,欢迎关注. Github 地址:https://github.com/sec-bit/learning-zkp/blob/mas ...

  9. 零知识证明学习(一)—— 初始零知识证明

    初始零知识证明 零知识证明(Zero-Knowledge Proofs,ZKP)背景知识,主要介绍一下研究的动机 这里我简单介绍一下背景知识,希望能引起你们研究的兴趣! 起源 Goldwasser等人 ...

最新文章

  1. 新视界,你好!_只愿与一人十指紧扣_新浪博客
  2. 上汽集团金忠孝: 人工智能时代的汽车将发生颠覆的变革
  3. c#学习之Socket网络编程
  4. 雷军藏太深!除小米、迅雷外,还有这么多耳熟能详的企业?
  5. Android HandlerThread和IntentService
  6. (转)智能投顾面临的法律合规问题及国际监管经验
  7. Linux安装教程(超详细版)
  8. android ui 开发界面量具 尺子,android尺子的自定义view——RulerView详解
  9. IDEA中进行spring项目开发配置文件中如何导入spring命名空间
  10. 历届全国大学生GIS应用技能大赛试题及数据
  11. 在杭州云栖大会,我们看到了一个新的阿里巴巴
  12. HDU 5442 (串的最大表示+KMP)
  13. python处理netcdf_Python处理netCDF文件
  14. 强烈推荐这 6 款 API 测试工具,绝对有一款没听过
  15. win10如何获得管理员权限
  16. CSS3做齿轮旋转的动画
  17. 社交APP经典死法18种,听野路子产品菜狗怎么说
  18. PinkRabbit写情书(map函数)
  19. AT24C04【EEPROM】iic时序解读
  20. 洪九果品上市:年营收百亿市值187亿港元 阿里是股东

热门文章

  1. python把文字矢量化_这个python函数可以被矢量化吗?
  2. android自定义水波纹,Android自定义View——实现水波纹效果类似剩余流量球(示例代码)...
  3. python最优分箱计算iv值_Python计算woe和iv值
  4. 基于PU-Learning的恶意URL检测——半监督学习的思路来进行正例和无标记样本学习...
  5. fopen和fopen_s用法的比较
  6. vue从创建到完整的饿了么(12)miste.vue
  7. 对JDBC的一些理解
  8. squidguard实现
  9. More Effective C++读书笔记(二)
  10. linux如何添加route,Linux主机添加路由 route(示例代码)