如何保证k是随机的¶
来源:
密码学引论 / digital_signature/ElGamal/如何保证k是随机的.md
Q:如何确保k是随机生成的,即使用一些随机数生成器,也不能消除掉碰撞的风险
对,不能从数学上“绝对确保”随机 (k) 永不碰撞。只能做到:
碰撞概率低到可以忽略,或者干脆不用真随机 (k),改用确定性 (k)。
在 ElGamal / DSA / ECDSA 这类签名里,(k) 是命门。只要 (k) 重复、偏弱、可预测,就可能泄露私钥。
真随机生成 (k):只能降低碰撞概率¶
假设 (k) 在一个很大的范围里均匀随机选,比如:
其中 (q) 是一个 256 bit 左右的大素数,那么可选空间大约是:
如果签名次数是 (n),根据生日悖论,碰撞概率大约是:
比如你签名 (2^{32}) 次,碰撞概率大约是:
这个概率极低,现实中可以认为不可能发生。
所以正常做法是:
- 使用密码学安全随机数生成器;
- 每次生成新的 (k);
- 检查 (1 \le k \le q-1);
- 必要时检查 (\gcd(k, p-1)=1),这是 ElGamal 原始签名里的要求。
但是你说得对:概率上仍然不是零。
更现代的做法:确定性生成 (k)¶
为了避免随机数生成器出问题,DSA/ECDSA 常用一种思路:
也就是说,(k) 不完全靠随机数,而是由:
- 私钥 (x)
- 消息哈希 (H(m))
通过安全的伪随机函数生成。
典型方案是 RFC 6979 deterministic k。
它的思想是:
对同一个私钥和同一个消息,(k) 固定; 对不同消息,(k) 看起来像随机数; 不依赖系统随机数质量。
这样可以避免:
- 随机数生成器坏掉;
- 熵不足;
- 两次刚好生成相同的 (k);
- VM 快照、嵌入式设备重启导致随机状态重复。
但确定性 (k) 也不是万能的¶
确定性 (k) 的问题是:
如果私钥 (x) 泄露,那 (k) 也能被重算出来。不过这不是额外问题,因为私钥泄露本来签名系统就完了。
还有一个问题是侧信道攻击。
即使 (k) 生成得很好,如果计算过程中泄露了:
或者泄露了 (k) 的部分比特,也可能被 lattice/HNP 攻击恢复私钥。
所以还要保证:
- 模逆计算尽量常数时间;
- 标量乘法不要泄露分支信息;
- 不要打印、缓存、复用 (k);
- 签名失败时不要重用同一个 (k)。
原始 ElGamal 签名里还要注意 \(gcd(k,p-1)=1\)¶
因为签名公式是:
所以需要:
否则 \(k^{-1} \pmod{p-1}\) 不存在。
因此生成 (k) 时不能只是随机取一个数,还要检查:
如果不满足,就重新生成。