解除Fiat-Shamir的安全隐患
Fiat-Shamir变换是零知识证明(ZKPs)和安全多方计算(MPC)的重要基础构件。它能将基于交互式协议的零知识证明转换为非交互式版本,本质上将对话过程转化为文档形式。这种能力是SNARKs和STARKs等核心技术的基石。
然而与多数密码学工具类似,Fiat-Shamir变换的实际应用比表面看起来更加微妙,一旦实现错误可能导致灾难性后果。针对此类错误的频繁出现,Trail of Bits发布了名为Decree的新工具,帮助开发者规范Fiat-Shamir转录过程并简化上下文信息的集成。
Fiat-Shamir技术概述
多数零知识证明遵循三步协议结构:
- Peggy向Victor发送一组值的承诺
- Victor回复随机挑战值
- Peggy返回整合了步骤(1)承诺值和步骤(2)挑战值的响应集
虽然步骤(1)和(3)因协议而异,但步骤(2)始终保持一致且是Victor唯一需要参与的环节。Fiat-Shamir变换通过将证明的公开部分(称为证明转录)输入哈希函数,并利用哈希输出生成挑战值,从而消除Victor生成随机挑战的需求。该机制需确保:
- Peggy无法控制生成的挑战结果
- 生成挑战后无法修改承诺值
- Victor可通过承诺信息重现相同挑战值
常见失败模式
实现规范缺失
在实际代码审查中,常见转录值为临时构建结构,其包含的值列表、顺序和数据格式仅能通过代码逆向推导。这种松散实现方式在证明系统中存在严重安全隐患。
形式化规范错误
学术论文在描述Fiat-Shamir变换时,若仅简单提及"可通过Fiat-Shamir变换实现非交互化"而缺乏详细规范,会将实现细节完全交由开发者处理。最危险的情况是作者提供未经验证的示例(如Bulletproofs论文中的原始示例),导致大量密码学家基于错误实现进行开发。
规范执行缺失
即使存在转录规范,验证其执行也极具挑战性。现代证明系统的复杂性导致:
- 转录值可能存在于多层子例程中
- 条件语句中容易遗漏转录值添加
- 转录相关调用可能分散在不同模块中
- 复杂计算产生的值容易在代码噪声中被忽略
Decree解决方案
Trail of Bits推出的Rust库Decree通过以下机制解决上述问题:
强制规范执行
初始化Fiat-Shamir转录时要求预先定义:
- 必需的转录值列表
- 预期挑战值列表
系统会主动检测以下错误行为:
- 未提供全部预期值前生成挑战
- 添加规范外值到转录中
- 重复添加已定义值
- 不按顺序请求挑战
基于Merlin的架构
Decree构建于成熟的Merlin库之上,管理底层Merlin转录的访问而不替换其密码学内部机制。例如初始化代码:
|
|
添加值时顺序无关(最终按字母顺序排序),但生成挑战时必须按声明顺序进行。
多阶段协议支持
Decree支持扩展转录以处理多阶段证明,通过扩展调用明确标识协议阶段边界,同时保留所有先前状态信息。
Inscribe特征集成
通过可推导的Inscribe特征,开发者可为包含命名成员的结构体指定上下文信息(如椭圆曲线参数)。例如Schnorr证明的实现:
|
|
通过#[inscribe(skip)]标记z成员,其他值将自动添加到转录中,完成后即可将包含z值的证明发送给验证者。
总结
Decree通过结构化规范定义和强制执行机制,帮助开发者避免Fiat-Shamir实现中的常见陷阱,同时通过Inscribe特征确保重要上下文数据的默认包含。虽然完全避免规范错误仍具挑战性,但至少使错误更易发现、测试和修复。