Kyber(ML-KEM)入门
《应用后量子密码学》本章的全部代码:共 15 段,其中 15 段可在此运行。编辑任意单元格,然后点击运行。
书中的代码片段在一章之内层层相依,但 Sage Cell 内核每次只运行一个单元格,运行后不保留任何状态,因此每个单元格都会用 apqc_book 重放此前的代码。这一调用是在书中原有代码之外唯一添加的内容。
代码 1:玩具版中采用的简化
真实的 ML-KEM 标准使用了许多精巧的机制。在玩具版中,我们只保留核心思想:
尽管这些简化幅度很大,数学骨架依然相同。对于模维数,我们也把 k 从 2,3,4 缩减为 k=2,以便手工检查各个对象。
代码 2:建立环
我们定义一个模 x⁸+1 的多项式环。此后构建的每个对象都位于这个商环 R_q 中。
代码 3:建立环
代码 4:构建模:多项式的向量与矩阵
对于 Kyber512,模维数为 k=2。这意味着秘密不是一个多项式,而是由 k 个多项式组成的向量,公开矩阵 A 是一个由多项式组成的 k × k 矩阵。
代码 5:生成小噪声
在真实的 Kyber 中,噪声从中心二项分布(CBD)中采样,这是后面某一章的主题。对于玩具版,我们只使用取值于 {-1,0,1} 的小系数。
代码 6:密钥生成
模 LWE 形式与标准 LWE 形式非常接近:
我们按如下方式实现它。
代码 7:验证密钥生成过程
我们可以打印矩阵及所得的公开值,以检查其形状和类型是否符合预期。
代码 8:编码一个消息比特
在玩具版中,消息被简化为单个比特。在真实方案中,消息编码要微妙得多;这里我们只是把一个比特映射为零,或映射为模数范围中间附近的一个值。
代码 9:加密
为了加密一个消息比特,我们采样一个随机向量 r 和两个噪声项 e₁,e₂。核心方程为
代码 10:解密
解密步骤使用秘密钥 s。其主要思想是:在代数展开过程中,涉及 A 和 s 的项相互抵消,只留下少量噪声和编码后的消息。
代码 11:解密
我们通过比较到两个编码中心 0 和 ⌊ q/2⌋ 的循环距离来恢复比特。特别地,域元素 16 表示 -1,必须被识别为接近编码后的零,而不是消息为一的值。
代码 12:整合所有部分
一次完整的玩具版运行如下所示。
代码 13:为什么该方案有时会失败
这个玩具版构造仍然可能频繁失败,因为 q=17 非常小,而且累积误差并不像 ML-KEM 中那样受到约束。它演示的是抵消与循环译码,而不是一个可靠的加密方案。在真实的 ML-KEM 中,参数经过调校,使解密失败概率极小。
一个简单的实验是把噪声生成器从
代码 14:为什么该方案有时会失败
改为更大的范围,例如
代码 15:为什么该方案有时会失败
甚至