# zk-Snark开发入门篇之circom开发 **Published by:** [Mobius](https://paragraph.com/@0xmobius/) **Published on:** 2022-07-14 **URL:** https://paragraph.com/@0xmobius/zk-snark-circom ## Content 由于已有些许基于circom circuit的zkp开发经验,所以本文就围绕circom开发来做一个入门级report。首先,对circom的特点、开发流程做了一个简要介绍;而后,分享了一些常用的circom库及用例;最后,以Tornado为例做了一个应用案例分析。Part 1. Circom开发概述Circom是一个底层用rust实现的编译器,它可以编译用circom语言实现的circuit。它将circuit编译的结果以contraints的形式输出,这些constraints能被用于计算相应生成逻辑的proof。Single Circuit上图的circuit在最后一行 s3 <= 1 - s1 * s2 设置了constraint,并将 s3 输出为计算结果。需要注意的是,circom的input默认为private,output默认为public,同时,这些信号的可视性都可以通过显式定义进行修改。Composable Circuit如上图,通过对单个电路的组合,可以实现功能各异的复杂电路,并且在工程上也能通过调用circom库避免重复造轮子。Circuit开发流程配置开发环境开发和编译circuit (1) --r1cs生成二进制的constraint文件; --wasm生成用于产生witness的文件.circom xxx.circom --r1cs --wasm --sym --c (2) 生成描述circuit描述snarkjs r1cs info xxx.r1cs js生成witness (以groth16为例), 用于链下测试circuit运算正确性const circuit = await wasm_tester("xx.circom"); const INPUT = { "xx": xx, "xx": xx } const witness = await circuit.calculateWitness(INPUT, true); 生成proof (1) 下载trusted setup phase1 参数wget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_10.ptau (2) line1: 导入trusted setup phase 1参数 (3) line2: 进行phase2 trusted setupsnarkjs groth16 setup xxx.r1cs powersOfTau28_hez_final_10.ptau circuit_0000.zkey snarkjs zkey contribute circuit_0000.zkey circuit_final.zkey --name="1st Contributor Name" -v -e="random text" snarkjs zkey export verificationkey circuit_final.zkey verification_key.json (4) 编译输出solidity verifier脚本snarkjs zkey export solidityverifier circuit_final.zkey Verifier.sol (5) js脚本生成proof,public signalconst { proof, publicSignals } = await groth16.fullProve(Input{xxx}, "xxx.wasm","circuit_final.zkey"); 链下验证proofsnarkjs groth16 prove xxx.zkey witness.wtns proof.json public.json 链上验证proof (1) 生成solidity calldataconst calldata = await groth16.exportSolidityCallData(proof, publicSignals); Part 2. Circom开发常用库Circomlib包括加密原语的Circom实现、条件语法实现:条件语法实现: mux1.circom; mux2.circom; mux3.circomhash function: poseiden.circomdigital signature algorithm: eddsa.circomCircomlib-matrix矩阵计算实现:矩阵加乘运算: matAdd.circom; matElemMul.circom; matElemPow.circom; matElemSum转置:transpose.circomtrace: trace.circomsnarkjszkSnark的js和Web Assembly实现:实现trusted setup multi-party ceremonies, 包括universal powers of tau ceremony以及phase2 ceremony可直接应用在node.js和浏览器中底层加密原语通过wasm实现,使用并行计算提升效率Part 3. Circom应用案例 —— Tornado cashTornado cash的core版本只支持少数可选面值的匿名转账;在升级到nova版本后,由于通过UTXO的账本数据结构进行记账,在功能上实现突破,目前可以实现自定义任意面值的匿名转账。此外,有很重要的一个技术点:不论是core版本还是nova版本都使用了Merkle Tree Root数组链上存证校验。Tornado-coreTornado-core的账本数据结构较为简单,使用包含nullifier和secret信息(这两者都在链下随机生成,并由用户保管)的commitment作为转账凭证,通过验证nullifier状态避免double spending。链上链下的数据一致性则通过MerkleTree Root数组链上存证的方式进行校验。生成commitmentfunction generateDeposit() { let deposit = { secret: rbigint(31), nullifier: rbigint(31), } const preimage = Buffer.concat([deposit.nullifier.leInt2Buff(31), deposit.secret.leInt2Buff(31)]) deposit.commitment = pedersenHash(preimage) return deposit } 取款校验circom核心逻辑:校验nullifier和MerkleTree Root// verify nullifier component hasher = CommitmentHasher(); hasher.nullifier <== nullifier; hasher.secret <== secret; hasher.nullifierHash === nullifierHash; // verify commitment based on hash(secret, nullifier), so which commitment is used for withdrawal is not revealed component tree = MerkleTreeChecker(levels); tree.leaf <== hasher.commitment; tree.root <== root; for (var i = 0; i < levels; i++) { tree.pathElements[i] <== pathElements[i]; tree.pathIndices[i] <== pathIndices[i]; } 可选面值的局限性由于core版本的记账数据结构不能对金额进行拆分,如果不使用固定面值,则会由于面值信息将存款人和提款人的信息联系上,从而使匿名转账在实作中失效。Tornado-nova相较于core版本,nova版本在设计理念上的创新,主要在于借鉴了Bitcoin的UTXO账本数据结构。它将每一笔转账以UTXO链式转移的方式实现,这样就使得转账金额可拆分,即时存款人和提款人将任意的存款金额信息公开,也可以通过拆分金额交易的方式实现匿名转账。(由于nova版本代码较长,在此就不贴出)UTXOUTXO的数据结构包含:金额、随机数salt、index;生成上链存证MerkleTree Root的叶子节点为UTXO的commitment(即金额、随机数salt以及公钥的poseidon哈希);nullifier为commitment、index以及私钥的poseidon哈希。keypair解锁UTXOTX中未解锁的outputs(即在使用时作为下次交易的inputs)需要使用仅由用户生成并持有的keypair进行解锁。交易circom核心逻辑校验commitment、nullifier以及与MerkleTree Root的一致性。Referencehttps://docs.circom.io/https://github.com/enricobottazzi/ZKversehttps://github.com/iden3/circomlibhttps://libraries.io/npm/circomlib-matrixhttps://github.com/iden3/snarkjshttps://github.com/tornadocash/tornado-corehttps://github.com/tornadocash/tornado-nova ## Publication Information - [Mobius](https://paragraph.com/@0xmobius/): Publication homepage - [All Posts](https://paragraph.com/@0xmobius/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@0xmobius): Subscribe to updates - [Twitter](https://twitter.com/___Mobius___): Follow on Twitter