ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

零知识证明:我如何证明“我知道秘密”,却不告诉你秘密?

零知识证明:我如何证明“我知道秘密”,却不告诉你秘密? 零知识证明我如何证明我知道秘密却不告诉你秘密我有一个秘密我想让你相信我确实知道它但又不愿意把秘密本身交给你。直觉上这两件事似乎是矛盾的——证明和保密怎么可能同时成立密码学给出的答案是可以。这就是零知识证明Zero-Knowledge Proof简称 ZKP要解决的问题。零知识证明中通常有两个角色Prover证明者真正知道秘密想证明这一点Verifier验证者不知道秘密但想确认 Prover 没在说谎。一句话概括它的目标证明我知道而不是告诉你我知道什么。下面先从一个经典的故事讲起建立直观感受再把它变成严格的数学。一、阿里巴巴的洞穴用随机挑战来证明想象一个环形洞穴入口在 A里面绕成一个环左右两边分别是 B 和 C最后汇合在 D。B 和 C 之间有一扇上了锁的门只有知道密码的人才能打开它。A / \ / \ B C \ / \ / DAlice 声称自己知道这扇门的密码Bob 想验证她的话但 Alice 不愿把密码说出来。协议这样进行并重复很多轮Alice 从 A 进入洞穴随机选择走左边B还是右边C。Bob 站在 A 处看不到她走了哪一边。Bob 随机喊出一个方向例如从右边 C 出来。如果 Alice 真的知道密码她总能穿过中间的密门从 Bob 指定的那一边出来如果她不知道密码只有当 Bob 恰好喊出她进来的那一边时她才能原路返回、蒙混过关。单看一轮一个不知道密码的人也有 50% 的概率撞对。但 Bob 每轮都随机喊重复nnn轮之后蒙混过关的概率降为P(骗过 Bob)(12)n P(\text{骗过 Bob}) \left(\frac{1}{2}\right)^nP(骗过Bob)(21​)n只要轮数足够多这个概率就小到可以忽略。于是 Bob 被说服了Alice 确实知道密码——而他全程没有得知密码本身。这个故事已经包含了零知识证明最核心的结构Prover 先行动 → Verifier 随机提问 → Prover 用秘密作答 → Verifier 检查答案接下来我们把这个故事变成严格的密码学协议——Schnorr。二、Schnorr把洞穴变成数学Schnorr 协议Schnorr Identification Protocol解决的问题非常明确证明者想证明自己知道一个秘密xxx使得ygxy g^xygx但全程不透露xxx。2.1 公开参数选择一个循环群GGG及其生成元ggg二者公开。Prover 随机选取秘密xxx计算并公开ygx y g^xygx于是公开的信息是ggg和yyy秘密是xxx。Prover 要证明我知道xxx但不能把xxx发出去。2.2 三步交互Schnorr 只有三步步骤谁做什么CommitmentProver随机选rrr计算tgrt g^rtgr发送tttChallengeVerifier随机选ccc发送cccResponseProver计算srcxs r cxsrcx发送sss用一张图表示关键点在于Prover 发送ttt时还不知道ccc会是多少所以rrr的选取无法看答案下注而xxx从头到尾都没有离开过 Prover它只藏在srcxs r cxsrcx里。2.3 验证等式为什么成立Verifier 手上有ggg、yyy、ttt、ccc、sss只需要检查一个等式gs?t⋅yc g^s \stackrel{?}{} t \cdot y^cgs?t⋅yc它成立的原因是一行代数gsgrcxgr⋅(gx)ct⋅yc g^s g^{r cx} g^r \cdot (g^x)^c t \cdot y^cgsgrcxgr⋅(gx)ct⋅yc如果 Prover 真的按srcxs r cxsrcx计算等式必然成立反之一个不知道xxx的人无法让这个等式成立。2.4 为什么它既可信又零知识可信Soundness / 知识证明假设一个作弊者不知道xxx却能在同一个ttt下正确回答两个不同的挑战c1≠c2c_1 \neq c_2c1​c2​得到s1s_1s1​、s2s_2s2​那么xs1−s2c1−c2 x \frac{s_1 - s_2}{c_1 - c_2}xc1​−c2​s1​−s2​​也就是说能应付所有挑战的人本质上一定知道xxx。这正是 Schnorr 被称为知识证明的原因。反过来不知道xxx的人只能像洞穴故事里那样靠运气蒙重复多轮后失败的概率趋近于 1。零知识Zero-KnowledgeVerifier 拿到了ttt、ccc、sss能不能反推出xxx由srcxs r cxsrcx似乎xs−rcx \frac{s - r}{c}xcs−r​但 Verifier 并不知道rrr——它只拿到tgrt g^rtgr。要从tgrt g^rtgr恢复rrr等于解离散对数问题在合适的群中这是计算上困难的因此 Verifier 无法从交互中恢复秘密xxx。更严格地说Schnorr 的零知识性由模拟Simulation保证即使不知道xxx只凭公开信息也能构造出与真实交互无法区分的记录。这说明交互过程本身没有向 Verifier 泄露关于xxx的任何额外信息——而不只是没把xxx发出去这么简单。2.5 从这里走向现代 ZKPSchnorr 的价值不仅在于它本身更在于它是理解现代零知识证明的入口它的承诺—挑战—响应结构是Σ 协议Σ-Protocol的典范把随机挑战ccc换成哈希cH(t,m)c H(t, m)cH(t,m)就是Fiat-Shamir 变换可以把交互式协议变成非交互式在此基础上稍作调整就得到Schnorr 签名。从 Schnorr 出发可以一路走向 ZK-SNARK、ZK-STARK 等现代系统。三、现实世界零知识证明有什么用零知识证明的价值在于现实里我们常常只需要证明一个结论成立而不需要交出支撑这个结论的全部隐私数据。3.1 年龄证明只证明我已满 18 岁某网站注册要求必须年满 18 岁。传统做法是出示身份证网站会看到姓名、身份证号、出生日期、住址等一系列信息——但它真正需要的其实只有一条Age≥18 Age \ge 18Age≥18借助零知识证明用户可以用身份凭证在本地生成一个证明网站验证后只得到已满 18 岁这个结论而不知道姓名、身份证号、具体生日。这就把查看原始信息变成了验证信息对应的事实。3.2 区块链证明资产但不公开全部交易区块链是 ZKP 另一个重要的应用场景。例如 Alice 想证明自己拥有一笔满足某些条件的资产传统方式需要把相关数据全部公开而引入零知识证明后验证者只需要确认Verify(Proof)True Verify(Proof) TrueVerify(Proof)True而不必看到证明背后的完整数据。这正是 ZK-SNARK、ZK-STARK 在隐私计算和区块链领域备受关注的原因。3.3 JWT 是零知识证明吗——不是但可以结合这里有一个常见的误解JWT 本身不是零知识证明。JWT 的思路是把用户身份/声明Claims打包由可信方签名服务器验证签名后即可信任。例如{sub:alice,role:admin,exp:1790000000}服务器验签后能确认这些声明来自可信签发方、且未被篡改但声明内容本身是可以直接读取的——服务器知道你是 Alice、是 admin。它并没有实现证明我是 Alice却不告诉你我是 Alice。JWT≠ZKP \text{JWT} \neq \text{ZKP}JWTZKP但两者可以组合。假设可信机构给用户签发了一份包含姓名、生日的数字凭证网站只要求证明我已满 18 岁。传统 JWT 会把姓名和生日一并带上而引入零知识证明后用户可以把凭证转成一个只证明年龄达标的证明{age_over_18:true,proof:ZKP...}服务器最终只知道已成年不知道姓名和具体生日。于是分工变得清晰JWT 负责承载认证结果或声明ZKP 负责证明这个声明确实成立。二者不是同一种技术但可以互相配合。结语从告诉你到证明给你看回头看开头的问题。传统的方式是我知道密码。 → 那你告诉我密码。 → 密码是 OpenSesame123。秘密被证明了但秘密也泄露了。而零知识证明试图做到的是我知道密码。 → 那我来验证你。 → Challenge → Response → 验证通过 ↓ 好我相信你知道。 但我依然不知道密码。从 Schnorr 的Commitment → Challenge → Response到现实中的身份认证、隐私证明、区块链、隐私身份本质上回答的是同一个问题当我们只需要知道事情是否成立为什么一定要把证明它所需的全部秘密交出去这就是零知识证明最值得理解的地方。
返回列表