密码学承诺方案:从哈希承诺到 Pedersen 承诺的数学原理
摘要:密码学承诺方案是一种"加密后锁定"的原语,允许承诺方绑定一个值,同时在 reveal 阶段验证该值。本文详细分析哈希承诺和 Pedersen 承诺的数学构造与安全属性。
一、承诺方案定义
1.1 核心概念
承诺方案涉及两个参与者:
- 承诺方(Committer):锁定一个值
- 验证方(Verifier):后续验证该值
1.2 安全属性
| 属性 | 定义 | 安全含义 |
|---|---|---|
| 隐藏性(Hiding) | 承诺方无法从 Commit 值获知消息 | 防止信息泄露 |
| 绑定性(Binding) | 承诺方无法改变已承诺的值 | 防止篡改 |
二、哈希承诺方案
2.1 构造方法
最简单直接的承诺方案:
CODE
Commit(m) = H(m || r)
Reveal(m, r) = (m, r)
Verify(m, r) = (Commit == H(m || r))其中:
m:要承诺的消息r:随机数(nonce)H:密码学哈希函数(如 SM3、SHA-256)
2.2 安全性分析
隐藏性证明:
- 由于 H 是单向函数,无法从 H(m||r) 反推 m
- 随机数 r 增加了熵,使暴力破解不可行
- 要改变承诺值,需要找到碰撞 H(m||r) = H(m'||r')
- 对于安全哈希函数,计算碰撞的计算复杂度为 O(2^n/2)
2.3 局限性
| 问题 | 说明 | 解决方案 |
|---|---|---|
| 需要信任哈希函数 | 如果 H 被攻破,方案失效 | 使用已验证的哈希算法 |
| 无同态性 | 无法对承诺值进行计算 | 使用 Pedersen 承诺 |
三、Pedersen 承诺方案
3.1 构造方法
Pedersen 承诺由 Victor Shoup 于 1991 年提出,基于离散对数问题:
CODE
Commit(m, r) = g^m × h^r mod p其中:
p:大素数g, h:生成元,满足log_g(h)未知m:消息(通常为整数)r:随机数
3.2 参数生成
安全参数生成:
- 选择安全素数 p, q(q | p-1)
- 选择生成元 g = h^q mod p
- 确保离散对数问题在阶为 q 的子群中困难
PYTHON
from Crypto.PublicKey import ECC
from Crypto.Hash import SM3
import os
def generate_pedersen_params(bits=2048):
"""生成 Pedersen 承诺参数"""
# 1. 生成安全素数 p, q
p = generate_safe_prime(bits)
q = (p - 1) // 2
# 2. 生成生成元 g, h
h = random_generator(p) # 阶为 q 的元素
g = pow(h, 2, p) # g = h^2 mod p
return p, q, g, h
def commit(m: int, r: int, g: int, h: int, p: int) -> int:
"""Pedersen 承诺"""
return pow(g, m, p) * pow(h, r, p) % p3.3 安全属性证明
隐藏性证明:
- 给定 C = g^m × h^r mod p
- 由于 log_g(h) 未知,对于任意 m',都存在 r' 使得 C = g^m' × h^r'
- 因此无法从 C 推断 m
- 要找到 (m, r) ≠ (m', r') 使得 g^m × h^r = g^m' × h^r' mod p
- 等价于找到离散对数 log_g(h)
- 假设离散对数问题困难,则绑定性成立
3.4 同态性质
Pedersen 承诺具有加法同态性:
CODE
Commit(m1, r1) × Commit(m2, r2) mod p
= g^(m1+m2) × h^(r1+r2) mod p
= Commit(m1+m2, r1+r2)应用:
- 电子投票:密文相加得到总票数
- 私有集合求交:保护隐私的同时计算交集
- 盲签名:签名者不知道签名内容
四、应用场景
4.1 电子投票
问题:如何确保投票隐私同时防止重复投票?
方案:
- 每个选民对投票 c = Commit(vote, randomness)
- 收集所有承诺值
- 使用零知识证明验证投票有效性
- 对承诺值进行同态加法得到总结果
- 解密总结果
4.2 盲签名
流程:
CODE
1. Alice 选择随机数 r,计算 C = Commit(m, r)
2. Alice 将 C 发送给 Bob(签名者)
3. Bob 对 C 进行签名,返回 σ
4. Alice 从 σ 中提取对 m 的签名安全保证:
- Bob 不知道 m(隐藏性)
- Alice 无法篡改 m(绑定性)
4.3 零知识证明
Pedersen 承诺是零知识证明的基础构件:
场景:证明我知道 x 使得 H = g^x,但不知道 x 具体值。
协议:
CODE
1. Prover 选择随机 k,计算 T = g^k
2. Verifier 发送随机挑战 e
3. Prover 计算响应 s = k + e·x
4. Verifier 验证 g^s = T × H^e五、实现注意事项
5.1 随机数选择
要求:
- 随机数必须足够长(建议 ≥ 256 位)
- 必须使用密码学安全随机数生成器
PYTHON
# ❌ 错误:使用伪随机数
r = random.randint(0, p)
# ✅ 正确:使用 CSPRNG
r = os.urandom(32)5.2 参数验证
验证清单:
- [ ] p 是安全素数
- [ ] q = (p-1)/2 也是素数
- [ ] g, h 的阶为 q
- [ ] log_g(h) 无法计算
5.3 性能优化
| 优化方法 | 说明 | 效果 |
|---|---|---|
| 预计算 | 预计算 g^m 表 | 加速多次承诺 |
| 批处理 | 批量验证承诺 | 减少计算次数 |
| GPU 加速 | 并行计算指数 | 提升吞吐量 |
六、与国密的结合
6.1 SM3 哈希承诺
使用 SM3 作为哈希函数:
PYTHON
from gmssl import sm3, func
def commit_with_sm3(m: bytes, r: bytes) -> str:
"""使用 SM3 的承诺方案"""
data = m + r
return sm3.sm3_hash(func.bytes_to_list(data))6.2 SM2 椭圆曲线承诺
基于 SM2 曲线的 Pedersen 承诺:
- 使用 sm2p256v1 曲线
- 消息和随机数在曲线阶 q 上
- 承诺值为曲线上的点
七、总结
密码学承诺方案是密码学的基础构件:
| 方案 | 隐藏性 | 绑定性 | 同态性 | 适用场景 |
|---|---|---|---|---|
| 哈希承诺 | ✅ | ✅ | ❌ | 简单场景 |
| Pedersen | ✅ | ✅ | ✅ | 复杂协议 |
- 简单场景使用哈希承诺
- 需要同态性的场景使用 Pedersen 承诺
- 随机数长度 ≥ 256 位
- 国密场景优先使用 SM2/SM3
参考
- Shoup, V. (1991). "Efficient Implementation of Legalizable Renunciation"
- Bellare, M., & Rogaway, P. (1993). "Commitment Schemes with User Error"
- GM/T 0003-2012《SM2 椭圆曲线公钥密码算法》
- GM/T 0004-2012《SM3 密码杂凑算法》