news 2026/10/13 2:42:36

Grin 中的 Switch Commitment(秘诺切换):Pedersen 承诺的隐私与绑定性安全阀设计解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Grin 中的 Switch Commitment(秘诺切换):Pedersen 承诺的隐私与绑定性安全阀设计解析
  • 区块链
  • Web3

【免费下载链接】grin

Minimal implementation of the Mimblewimble protocol.

项目地址:https://gitcode.com/gh_mirrors/gr/grin
点击查看免费下载

导读

本文围绕 Grin(Mimblewimble 协议的最小化实现)文档库中的 doc/switch_commitment.md 展开,系统讲解"承诺方案"(Commitment Scheme)这一密码学基础概念,以及 Grin 如何通过Switch Commitment(秘诺切换)技术,在保持 Pedersen 承诺完美隐匿性的同时,为"绑定性被意外破解"这一极端灾难场景预留一个向后兼容的安全开关。读完本文,你将掌握承诺方案的两大核心属性(隐匿性与绑定性)及其安全权衡、ElGamal 承诺与 Pedersen 承诺的关系,并能结合 keychain/src/keychain.rs、core/src/libtx/build.rs 等源码理解 Grin 中秘诺切换的实际实现方式。


一、承诺方案:把秘密锁进盒子里

在密码学中,承诺方案(Commitment Scheme)可以形象地理解为一个带锁的盒子:你可以把一样东西放进盒子里(例如一张写着秘密数字的纸条),锁上锁,然后把盒子交给另一个人(或公之于众)。

对方此刻并不知道盒子里的秘密数字是什么;而当你日后决定公布这个秘密、并希望证明"这确实是我最初想好的那个秘密(而不是后来改的)"时,你只需要把盒子的钥匙交给对方即可:

  1. 对方打开盒子;
  2. 将盒内的秘密与你刚刚公布的数字进行比对;
  3. 确认你自锁上盒子以来从未更改过秘密。

这就是"承诺(commit)"的含义:你在事先对秘密数字做出承诺,那么在承诺生成与公开揭示之间的任何时间点,你都无法再更改它。

1.1 哈希承诺:最朴素的实现

一个简单的承诺方案可以借助密码学哈希函数实现。例如 Alice 和 Bob 要玩"猜数字"游戏,Alice 想好了一个秘密数字29。在游戏开始前,Alice 计算:

hash( 29 + r )

并把结果公布给 Bob。其中r是一个随机选择的致盲因子(Blinding Factor)。它之所以必要,是因为如果没有r,Bob 完全可以把游戏中所有可能的数字逐一哈希,再与 Alice 公布的哈希值比对,从而提前猜出答案。

游戏结束时,Alice 只需公布秘密数字29和致盲因子r,Bob 自己重新计算哈希即可验证:Alice 在游戏过程中没有偷换数字。

1.2 Pedersen 承诺:具有同态性的进阶方案

更高级的承诺方案可以具备额外性质。例如 Mimblewimble 与机密交易(Confidential Transactions,CT)大量使用了Pedersen 承诺,它是一种同态(homomorphic)承诺。借用上面"盒子"的比喻:你可以把两个已上锁的盒子(盒子1 与 盒子2)相加,得到一个仍然上锁的新盒子;日后打开这个新盒子时,里面装着的秘密,恰好是盒子1 与盒子2 内秘密的总和。

在现实世界中,"两个盒子相加"听起来不可思议,但在椭圆曲线上,这一性质可以借助运算规则完美实现。关于 Pedersen 承诺在 Grin 中如何使用(包括致盲因子、超额值与内核偏移等细节),可进一步阅读 doc/intro.md(《Introduction to Mimblewimble》)。


二、承诺方案的两大属性与安全级别

无论哪种承诺方案,都可以从两个维度衡量其安全性,强弱则因方案类型而异:

  • 隐匿性(Hidingness,或称机密性 Confidentiality):承诺方案对秘密的保护程度。回到"盒子"比喻:攻击者没有钥匙时,要打开盒子(从而得知秘密数字)需要付出多大代价?
  • 绑定性(Bindingness):攻击者是否(以及有多难)能找到另一个不同的秘密,使其产生完全相同的承诺。若能做到,攻击者日后就能把承诺"打开"成另一个秘密,从而破坏承诺的绑定关系。

2.1 两种安全强度:计算性 vs 完美性

对于上述两个属性,可以区分出不同的安全级别。最常见的两种组合是:

  • 完美绑定(perfectly binding)+ 计算隐匿(computationally hiding);
  • 计算绑定(computationally binding)+ 完美隐匿(perfectly hiding)。

这里的"计算(computationally)"是指:该属性由底层数学问题的难度来保障——以现有的计算能力,在合理时间内无法求解(即今天无法被破解,因为现实世界的计算资源是有限的);而"完美(perfectly)"则是指:即使攻击者拥有无限计算能力,也不可能破坏该属性。

2.2 一个根本性的互斥:两者不可兼得

需要特别强调的是:任何承诺方案都不可能同时做到"完美绑定"和"完美隐匿"。这可以用一个思想实验来证明:

假设攻击者拥有无限计算能力,他可以对所有可能的值(以及所有可能的致盲因子)逐一生成承诺,直到找到一个与目标承诺相同输出的输入对。此时:

  • 若该方案是完美绑定的(即不存在两个不同的值产生同一承诺),那么这个匹配的输入值就是唯一的——攻击者据此可以直接识别出承诺内的原始值,隐匿性随之被破坏;
  • 反之,若方案是完美隐匿的,则必然存在多个输入值对应同一个承诺(否则无限算力的攻击者只需遍历所有可能值即可破解),这又意味着方案不可能完美绑定。

结论永远是妥协:两个属性不可能同时获得完美安全;一个属性若达到完美安全,另一个至多只能达到计算安全。

2.3 加密货币视角:隐匿性与绑定性的不同角色

在面向隐私的加密货币(如 Grin)中,这两个属性的意义截然不同:

  • 隐匿性(隐私价值):承诺方案被用来保护交易内容。发送方承诺自己要发送的币量,但对公众而言,具体金额必须保持私密——这依赖承诺方案的隐匿性。
  • 绑定性(经济价值):任何交易创建者都不能在事后把自己的承诺改写成另一个交易金额。如果可能,攻击者就能在某个 UTXO(未花费交易输出)中花费超出先前承诺的金额,从而凭空铸造新币;更糟的是,由于金额本身被隐藏,这种通胀行为甚至可能无法被发现。

因此,加密货币的合理诉求是:两个属性都必须在整个生命周期内持续安全。即便如此,仍然必须做出选择——到底采用哪种承诺方案。

2.4 看似艰难的取舍,其实答案清晰

如果要二选一:哪个属性需要完美安全,哪个只需计算安全?换句话说,假如承诺方案意外被攻破,我们更应当优先保住哪一个——经济健全性(杜绝隐藏通胀)还是隐私保证(隐私永不泄露)?

仔细分析会发现答案并不难:

  • 绑定性只在方案真正被攻破的那一刻才需要是完美的。在此之前,即使只是计算绑定也足够安全。而且绑定只影响"交易创建时"这一时点,不会追溯影响过去的交易。
  • 隐匿性则必须永远得到保证。因为一旦承诺方案被攻破,攻击者可以回溯整条链,解除历史交易的致盲,从而追溯性地破坏所有过往交易的隐私。

也就是说,对隐私导向的加密货币而言,隐匿性需要永久完美,绑定性只需在灾难时刻完美。这正是 Switch Commitment 设计的出发点。


三、Pedersen 承诺的属性:为什么需要一道"安全开关"

Pedersen 承诺的具体形式为:

v*H + r*G

其中v是输入/输出的金额,r是致盲因子,H与G是椭圆曲线上的两个生成点。

Pedersen 承诺是计算绑定且完美隐匿的:对于给定的承诺值v*H + r*G,可能存在另一对不同的r1、v1使得二者之和相同。即使你拥有无限算力、遍历所有可能的取值,也无法分辨哪一对才是原始输入(因此是完美隐匿)。

那么问题来了:如果 Pedersen 承诺的绑定性被意外破解,该怎么办?

3.1 常规思路的困境:换方案意味着全民搬币

一般加密货币面对承诺方案被攻破时,最直接的反应是更换承诺方案。但这带来一个严峻问题:更换方案后,必须用新方案重新创建交易输出,资金才能重新获得安全保障——也就是说,每一位持币者都必须把自己的币转移到新的交易输出。没有转移的币,就无法享受新承诺方案的保护。

更关键的是,这一切必须发生在方案真正被大规模攻破之前,否则既有的 UTXO 将无法再被假定为包含正确的金额。

3.2 Switch Commitment:只换验证方式,不换承诺本身

针对这一困境,《Switch Commitments: A Safety Switch for Confidential Transactions》("秘诺切换")论文给出了一个精妙的解决方案:

这类承诺允许仅通过改变揭示/验证流程来改变承诺的属性,而完全不需要改变承诺的创建方式。你"切换"到一套新的验证方案,并且它与"切换"发生之前很久就创建出来的承诺向后兼容。

这就是"switch(切换)"一词的由来:未来可以像拨动开关一样,仅仅改变验证程序,就能改变承诺在绑定性与隐匿性上的强度,而且这种切换对今天创建的承诺依然有效。


四、ElGamal 承诺:完美绑定的"预备方案"

为了说清楚 Switch Commitment 的原理,需要先引入一个新的承诺方案:ElGamal 承诺。它与 Pedersen 承诺结构非常相似,只是额外增加了一个元素——由致盲因子r与第三个生成点J相乘得到:

v*H + r*G , r*J

ElGamal 承诺是完美绑定的(按照互斥原则,它只能做到计算隐匿)。

关键洞察在于:如果我们把额外的r*J字段存储下来但暂时忽略它,那么v*H + r*G这部分完全可以继续当作普通 Pedersen 承诺使用;等到未来某一天,我们决定同时验证完整的 ElGamal 承诺,就可以立刻获得完美绑定的保护。

4.1 早期 Grin 的做法:显式存储 switch_commit_hash

在主网上线之前的 Grin 早期版本 中,正是采用了上述思路:将r*J的哈希值(即switch_commit_hash)附加到交易输出上。这样日后无需改动既有输出,即可验证完整的 ElGamal 承诺。

但这一方案有一个明显的代价:每个交易输出因此增加了 32 字节的体积。对于一条不断累积 UTXO 的公链来说,这是一笔不小的存储开销。

4.2 Tim Ruffing 的优化:把 ElGamal 承诺"嵌入"致盲因子

幸运的是,Mimblewimble 邮件列表上的Tim Ruffing(最初由Pieter Wuille提出)随后给出了一个更漂亮的方案,既保留同等优势,又无需为每个输出额外存储任何字段。

普通的 Pedersen 承诺是:

v*H + r*G

(v为输入/输出金额,r为真正随机的致盲因子,H、G为曲线上的两个生成点。)

优化思路是:让r不再是完全独立的随机数,而是由另一个随机数r'派生而来——先计算一个 ElGamal 承诺v*H + r'*G , r'*J,再将其哈希结果加到r'上,得到最终致盲因子:

r = r' + hash( v*H + r'*G , r'*J )

(其中J是曲线上额外的第三个生成点。)

这样构造出的r依然是完美有效的致盲因子——因为它仍然随机分布、无法被外界预测。但同时,r的构造过程已经"内嵌"了一个 ElGamal 承诺(即哈希括号中的v*H + r'*G , r'*J)。未来一旦需要强化绑定性,验证方只需校验这个嵌入的关系即可。

这个巧妙的想法使得后续 pull requests 得以从交易输出中移除switch_commit_hash,将秘诺切换能力"折叠"进 Pedersen 承诺本身,不再占用任何额外字节。


五、Grin 中的源码级实现

从当前仓库的源码看,Switch Commitment 已经贯穿 Grin 交易构建、密钥派生与范围证明(rangeproof)的各个环节。

5.1 SwitchCommitmentType:一枚可拨动的开关

在 keychain/src/types.rs 中定义了秘诺切换的类型枚举,并提供了与u8的双向转换(0 对应None,1 对应Regular):

pub enum SwitchCommitmentType { None, Regular, }

这正对应文档中"当前使用 Pedersen 承诺、但已内嵌 ElGamal 构造"的Regular模式,以及不启用切换的None模式。Keychaintrait 的derive_key、commit、sign等接口都接收SwitchCommitmentType参数(见 keychain/src/keychain.rs)。

5.2 密钥派生:调用底层 blind_switch

在 keychain/src/keychain.rs 中,derive_key依据切换类型分派:

match switch { SwitchCommitmentType::Regular => { Ok(self.secp.blind_switch(amount, ext_key.secret_key)?) } SwitchCommitmentType::None => Ok(ext_key.secret_key), }

Regular模式会调用底层secp的blind_switch——这正是文档所述"致盲因子由随机r'加上 ElGamal 承诺哈希计算得出"的落地实现(对应 secp256k1-zkp 库commitment/main_impl.h中的blind_switch逻辑)。而commit则是先derive_key再secp.commit(amount, key)(见 keychain/src/keychain.rs)。

5.3 交易构建与区块奖励:一律使用 Regular

在交易构建器 core/src/libtx/build.rs 中,无论是普通输入(input)还是 coinbase 输入(coinbase_input),都通过SwitchCommitmentType::Regular生成承诺;输出构建(output)同样显式使用Regular(见 core/src/libtx/build.rs),并配合注释"TODO: proper support for different switch commitment schemes"——表明当前所有交易输出统一采用内嵌秘诺切换的 Pedersen 承诺。

区块奖励输出也不例外:core/src/libtx/reward.rs 中计算reward(fees)后同样以SwitchCommitmentType::Regular生成承诺,保证 coinbase 输出与其他输出使用同一套安全属性。

5.4 范围证明与输出结构:不再有 32 字节负担

范围证明的创建与回放(rewind)流程中,SwitchCommitmentType也被嵌入证明消息(proof message),用于钱包找回金额、派生路径与切换类型(见 core/src/libtx/proof.rs 的create,以及 core/src/libtx/proof.rs 的rewind)。

同时,在 core/src/core/transaction.rs 中,Output结构只包含"输出标识(features + commitment)"与范围证明proof两个字段,并不存在独立的switch_commit_hash字段——这正是 Tim Ruffing 方案生效的直接证据:秘诺切换能力被压缩进了致盲因子的构造过程,每个输出不再承担额外的 32 字节。

5.5 测试与佐证

仓库中的测试同样印证了上述实现:

  • core/tests/transaction.rs 在构建交易测试中显式使用keychain::SwitchCommitmentType::Regular生成承诺与范围证明;
  • chain/tests/process_block_cut_through.rs 在区块处理的集成测试中以Regular模式生成 60 亿金额的承诺;
  • chain/tests/mine_simple_chain.rs 在挖矿测试中同样使用Regular构建输入输出。

这些测试表明:从单个输出、到交易、再到区块处理的全链路,Grin 都默认采用内嵌秘诺切换的 Pedersen 承诺。


六、结论:为"灾难"预留的一层额外保险

综上所述,Grin 与其他隐私加密货币一样使用 Pedersen 承诺,唯一的区别在于:随机致盲因子r是通过 ElGamal 承诺方案构造出来的。

这个看似微小的改动,实际上提供了一项重要的安全措施:

  • Pedersen 承诺本身已经是完美隐匿的,所以无论发生什么,隐私永远不会受到威胁,且不需要用户采取任何行动;
  • 万一承诺方案的绑定性被攻破,就可以通过一次软分叉启用秘诺切换:要求所有新交易验证完整的 ElGamal 承诺,以此证明自己的承诺没有破坏绑定性(杜绝凭空铸造)。

即便如此,灾难场景下用户依然保有选择权:

  • 继续交易:用户可以选择继续创建新交易。由于 ElGamal 承诺只是计算隐匿,这可能会牺牲隐私(且只涉及用户最后的 UTXO),但至少用户仍然能够动用自己的币;
  • 静默离场:用户也可以选择不再进行任何交易,从而完整保留隐私——因为旧交易只验证过完美隐匿的 Pedersen 承诺,过往隐私不受新验证规则影响。

现实中,隐私泄露对某些人而言可能比损失一笔加密货币更加致命。这是每个用户自己应当做出的判断,而秘诺切换恰恰把这种选择权交还给了用户。

需要特别澄清的是:这是一项专为灾难场景准备的保险措施,而不是常态化的机制。如果未来计算能力的进步使离散对数难题的困难性受到质疑,那么包括其他加密货币在内的大量加密系统都将急需把底层原语升级到面向未来的方案;秘诺切换只是在 Pedersen 承诺的绑定性被意外攻破时,为 Grin 额外提供的一层安全纵深。


延伸阅读

  • 秘诺切换的完整理论出处:《Switch Commitments: A Safety Switch for Confidential Transactions》(IACR ePrint 2017/237)
  • Pedersen 承诺与 Mimblewimble 交易原理:doc/intro.md
  • 本文中文版对应原文:doc/translations/switch_commitment_ZH-CN.md
  • 源码入口:keychain/src/types.rs、keychain/src/keychain.rs、core/src/libtx/build.rs、core/src/libtx/proof.rs、core/src/core/transaction.rs
  • 区块链
  • Web3

【免费下载链接】grin

Minimal implementation of the Mimblewimble protocol.

项目地址:https://gitcode.com/gh_mirrors/gr/grin
点击查看免费下载
上一篇:godogen 全自动游戏开发流水线演进全记录:从 GDScript 生成器到"仅文档运行时"的架构蜕变
下一篇:基于 Credential Access Boundaries 的降级凭证(Downscoping)实战:python-docs-samples 中的受限访问令牌实现

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 2:40:10

Windows下部署Copaw:飞书AI机器人接入全流程指南

部署 AI 机器人到办公 IM 这件事,我前后折腾过不少次,Copaw 算是其中让我觉得"安装到飞书集成"这条链路走得比较顺的一个。Copaw 本质上是一个把大模型能力接进飞书的机器人网关服务,你把它部署在 Windows 机器上,配置好…

作者头像 李华
网站建设 2026/10/13 2:36:11

线段树模拟费用流:高效解决产品销售利润最大化问题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 2:35:19

Zynq7020 Linux开发实战:环境搭建、SD卡启动与设备树配置

1. 为什么一块Zynq7020开发板值得折腾Linux实验手里这块Zynq7020开发板已经放了小半年,最近终于抽出时间把Linux相关的实验从头到尾跑了一遍。说实话,如果你之前只玩过单片机裸机开发,第一次接触Zynq系列的芯片,大概率会有点懵——…

作者头像 李华