libsnark库代码层次十分明晰。libsnark也得出了SNARK涉及算法的全貌,各种Relation,Language,Proof System。
为了更佳的分解R1CS电路,libsnark抽象化出有protoboard和gadget,便利开发者较慢搭起电路。在读者该示例代码前,请求仔细阅读libsnark的源代码分析:零科学知识证明 - libsnark源代码分析唯一有点失望的,libsnark没给个原始的电路结构实例,入门者想要搭起自己的电路,刚开始有点摸不着头脑。
为了便利入门者撰写自己的电路,同事写出了个基于libsnark结构电路,并分解并检验电路的实例:https://github.com/StarLI-Trapdoor/libsnark_sample入门者,可以基于这个示例研发自己的电路。自由选择默克尔树根作为电路的示例,因为在零科学知识证明的应用于中,大量的用于默克尔树根数据结构。
1 代码结构该示例结构了一条merkle路径的检验电路,分解并检验证明。merkle树根的深度为3,并且merkle树根的计算出来使用sha256散列函数。代码结构较为明晰,merkle目录中的main.cpp是主函数。
circuit目录下的merklecircuit.h是电路的构建。整个项目用cmake展开编译器。2 电路构建电路取名为MerkleCircuit,主要倚赖两个gadget:merkle_authentication_path_variable和merkle_tree_check_read_gadget。
merkle_authentication_path_variable获取了merkle树根的一条路径。merkle_tree_check_read_gadget检查等价一个叶子节点,网卓新闻网,否能计算出来出有准确的root。构建一个电路,主要构建两个接口函数:generate_r1cs_constraints - 分解R1CS,该电路比较简单,只要让倚赖的两个gadget,分解R1CS才可。generate_r1cs_witness - 给所有的变量展开赋值。
该电路,必须赋值的变量有root,leaf(叶子节点),和叶子节点设施的默克尔路径,以及默克尔路径对应的地址信息(也就是每一层的节点的方位,左边还是右边)。整个电路最简单的就是电路的构造函数,申请人变量,创立gadget。其中重点谈一谈,set_input_sizes函数。
libsnark的框架中,用于非常简单的区分public和private变量的模型。通过set_input_sizes函数,设置前几个变量为public变量。pb.set_input_sizes(root_digest-digest_size);也就是说,该电路的公开发表变量为root的bit个数。
3 分解和检验证明确认了电路的构建,想到main函数,如何分解和检验证明。在main函数中定义了merkle树计算出来必须的一些类型:typedef libff::default_ec_pp ppzksnark_ppT;typedef libff::Frppzksnark_ppT FieldT;typedef sha256_two_to_one_hash_gadgetFieldT HashT;FieldT配置文件是bn256椭圆曲线的的Fr,默克尔树根计算出来使用是sha256算法。
3.1 setup构建了generate_read_keypair函数,分解pk/vk。细心看一下generate_read_keypair函数,逻辑非常简单明晰:结构MerkleCircuit,在分解R1CS后,调用r1cs_gg_ppzksnark_generator分解pk/vk。protoboardFieldT pb; sample::MerkleCircuitFieldT, HashT mc(pb, tree_depth); mc.generate_r1cs_constraints(); r1cs_constraint_systemFieldT cs = pb.get_constraint_system(); return r1cs_gg_ppzksnark_generatorppzksnark_ppT(cs);pk存放在merkle_pk.raw文件中,vk存放在merkle_vk.raw中。3.2 proveprove逻辑,首先从输出参数结构一个原始的merkle树,并根据输出指定了默克尔路径。
通过generate_read_proof函数分解证明。该函数逻辑也较为明晰: protoboardFieldT pb; sample::MerkleCircuitFieldT, HashT mc(pb, tree_depth); mc.generate_r1cs_constraints(); mc.generate_r1cs_witness(pb, leaf, root, path, address, address_bits); return r1cs_gg_ppzksnark_proverppzksnark_ppT(proving_key, pb.primary_input(), pb.auxiliary_input());结构MerkleCircuit,在分解R1CS后,设置各个变量的值。接着通过r1cs_gg_ppzksnark_prover分解证明。
3.3 verify在得知vk,证明以及公开发表信息(root)的基础上,调用r1cs_gg_ppzksnark_verifier_strong_IC的模块已完成检验。这也就是verify_read_proof函数的逻辑。4 编译器和运营在编译器之前,实时该项目倚赖的libsnark库:git submodule update --init --recursive4.1 编译器mkdir build; cd build; cmake ..编译器已完成,merkle目录持续性分解merkle的可执行文件。
4.2 可靠设置(trusted setup)./merkle setup4.3 分解证明./merkle prove [data1] [data2] [data3] [data4] [data5] [data6] [data7] [data8] [index]prove命令,必须获取完整的3层merkle树根的8个叶子节点,并登录必须证明的第几个叶子节点对应的路径(index说明)。4.4 检验./merkle verify [root]其中,root信息是在prove中分解过程中打印机出来的root信息(也是公开发表信息)。如果检验通过,就解释不存在一条能分解root的merkle路径,虽然没公开发表路径的明确信息。
总结:libsnark库代码层次十分明晰,并抽象化出有protoboard和gadget,便利开发者较慢搭起电路。本文得出了一个基于libsnark库研发的原始电路示例。
示例构建了3层默克尔树根的一条默克尔路径的检验。其中默克尔树根使用sha256的散列函数。
本文来源:KUBET最新登陆网址-www.shiikikanae.com