场景
假设你想向某个网站证明你知道密码,但又不想直接暴露密码。这可以用零知识证明 (ZK-SNARKs) 来实现。
传统方法:
- 你输入密码,服务器检查密码是否正确。
- 服务器需要存储和处理你的密码,可能有泄露风险。
zk-SNARKs 方法:
- 你生成一个证明(Proof),表明你知道正确密码。
- 服务器验证该证明,无需知道密码本身。
实现思路
-
构造约束(电路)
设计一个数学问题,确保只有知道正确密码的人才能生成有效证明。- 输入:秘密密码 (x)
- 计算:哈希 (H(x))
- 约束:(H(x) = H_expected)(服务器存储的哈希值)
-
生成证明(Prover)
证明者(用户)使用 zk-SNARKs 生成一个证明,表明自己知道密码 (x) 且其哈希匹配。 -
验证证明(Verifier)
服务器只需检查 zk-SNARKs 生成的证明,而无需知道密码。
代码示例(Circom + SnarkJS)
使用 Circom 定义密码验证电路:
pragma circom 2.0.0;
template PasswordCheck() {
signal private input x; // 用户输入的密码
signal output valid;
signal expectedHash; // 服务器存储的哈希值(硬编码或输入)
expectedHash <== 123456789; // 示例哈希(实际应安全存储)
// 计算哈希并比较
valid <== (poseidon([x]) == expectedHash);
}
component main = PasswordCheck();
执行步骤
-
编译电路:
circom password.circom --r1cs --wasm --sym --c
-
生成密钥:
snarkjs groth16 setup password.r1cs pot12_final.ptau password_0000.zkey
-
用户生成证明:
node password_js/generate_witness.js password.wasm input.json witness.wtns snarkjs groth16 prove password_0000.zkey witness.wtns proof.json public.json
4.服务器验证证明:
snarkjs groth16 verify verification_key.json public.json proof.json
优点
✅ 密码不会泄露
✅ 服务器无需存储原始密码
✅ 即使服务器遭受攻击,密码仍然安全