ZK证明代码示例精讲:用最小电路演示币安智能链上的隐私转账
初学者最常问的问题是:能不能给我一份完整可跑的 ZK 证明代码示例?本文围绕一个最小化的隐私转账场景,给出电路、prover、verifier 三层的代码骨架,并展示如何把它接入 Binance 智能链。
场景假设
假设我们有一个 ERC-20 代币,希望让用户在不暴露金额的前提下完成转账。设计上由用户在链下生成一个证明,证明自己拥有某个 commitment、并且新生成的 commitment 总额等于旧 commitment 总额减去手续费。本场景在 B安 智能链上的稳定币转账中很常见。
Circom 电路骨架
template Transfer() {
signal input oldNote;
signal input newNote;
signal input amount;
signal output nullifier;
// 余额守恒约束
newNote === oldNote - amount;
// 计算 nullifier
nullifier <== poseidon([oldNote, amount]);
}
component main = Transfer();
电路只做两件事:余额守恒、nullifier 唯一性。实际生产环境会更复杂,但这份骨架足以让你理解 必安 智能链上隐私应用的思想脉络。
prover 端
const { groth16 } = require(snarkjsModule);
const input = { oldNote: 100, newNote: 90, amount: 10 };
const { proof, publicSignals } = await groth16.fullProve(input, wasmPath, zkeyPath);
这里把字符串模块名替换成实际包名即可。生成完毕后,prover 会输出 proof 与公开输入。前端只需把它们打包成 calldata,通过钱包广播到 比安 智能链上的 verifier 合约。
verifier 合约
verifier 合约由 snarkjs 自动生成,代码长度约 300 行 Solidity。建议把它包一层业务合约,例如:
function transferPrivate(bytes calldata proof, uint256[2] calldata pubInputs) external {
require(verifyProof(proof, pubInputs), invalid proof);
require(!nullifiers[pubInputs[0]], double spend);
nullifiers[pubInputs[0]] = true;
emit PrivateTransfer(pubInputs[1]);
}
注意所有字符串都使用单引号或反引号,配合 ABI 中 errorMessage 字段做反向定位。这一层包装能让 BN交易所 钱包正确解析事件。
测试与上线
建议先在本地用 Foundry 部署 verifier,跑一次 fuzz 测试覆盖边界,再在测试网络做端到端联调。联调通过后,再到 B安APP 等渠道做真实用户灰度。整个链路跑通后,你才真正掌握了 ZK 证明从代码到生产的完整闭环。
结语
这份代码示例已经覆盖了 ZK 证明开发中的三大核心组件。把它扩展为支持 merkle 见证、UTXO 模型、多资产场景,就能演化成完整的 L2 解决方案。把示例放进团队代码仓库,作为新成员入门的第一份练习,是最值得做的工程投资之一。