国密算法全栈安全能力系统化提升 - 第3节

双线性对:SM9的数学心脏

双线性对,说白了就是一种特殊的映射。它能把两个群里的元素,映射到第三个群里去。而且这个映射有个神奇的性质——它能把加法变成乘法。

我记得刚接触这个概念时,也觉得挺抽象的。直到我在一个实际项目中,需要设计基于身份的加密方案,才真正体会到它的威力。没有双线性对,SM9这类算法根本跑不起来。

Weil对与Tate对

双线性对有两大经典实现:Weil对和Tate对。它们都是定义在椭圆曲线上的。

Weil对:

  • 输入两个n阶点P、Q
  • 输出一个n次单位根
  • 计算复杂度较高

Tate对:

  • 输入一个n阶点P和一个任意点Q
  • 输出一个扩域元素
  • 计算效率更高,SM9用的就是它

核心区别:Tate对比Weil对少一次幂运算,效率提升约30%。在实际工程中,这30%可能就是能不能上线的分水岭。

双线性对的三个性质

为什么双线性对这么重要?因为它同时满足三个性质:

  1. 双线性:e(aP, bQ) = e(P, Q)^(ab)
  2. 非退化性:存在P、Q使得e(P, Q) ≠ 1
  3. 可计算性:存在高效算法计算e(P, Q)

你想想看,有了双线性,我们就能在椭圆曲线上做"乘法"了。这在以前是不可能的——椭圆曲线只有加法群结构。

我的经验:在实现SM9时,我建议优先选择Tate对。虽然Weil对在理论上更优美,但Tate对在实际工程中更友好。我曾经在两个方案之间犹豫,最后用Tate对把签名验证时间从200ms降到了120ms。

Miller算法:双线性对的计算引擎

双线性对的理论很美,但怎么算呢?Miller算法就是答案。

Miller算法的核心思想,说白了就是"边计算标量乘,边累积函数值"。它把双线性对的计算,分解成一系列椭圆曲线上的点加和点倍操作。

算法流程

我习惯把Miller算法分成三步:

  1. 初始化:设置f = 1,T = P
  2. 主循环:按Q的二进制展开,逐位处理
    • 每次先做倍点:T = 2T,更新f
    • 如果当前位为1:T = T + P,更新f
  3. 最终幂:对f做一次幂运算,得到最终结果
// Miller算法伪代码
function Miller(P, Q, n):
    f = 1
    T = P
    n_bits = binary(n)
    for bit in n_bits[1:]:  // 从次高位开始
        f = f^2 * line(T, T, Q)  // 倍点
        T = 2T
        if bit == 1:
            f = f * line(T, P, Q)  // 点加
            T = T + P
    return f^( (q^k - 1) / n )  // 最终幂

避坑指南:我曾经在实现Miller算法时,忽略了line函数的计算顺序。结果调试了整整两天,才发现是坐标系的选取问题。建议使用雅可比坐标系,可以减少求逆运算。

SM9中的双线性对应用

SM9是我国基于身份的密码标准。它用双线性对做了三件事:

功能 使用的对运算 计算次数
密钥封装 e(Ppub, Qid) 1次
签名验证 e(S, P) = e(H, Ppub) 2次
密钥交换 e(P1, P2) 2次

嗯,这里要注意。SM9用的是256位的BN曲线,Tate对的计算在普通PC上大约需要5-10ms。这个速度对大多数应用来说已经够用了。

关键点:SM9的安全性依赖于q-ABDHE假设。这个假设比传统的CDH假设更强,但换来了基于身份的便利性。在实际部署中,我建议优先使用SM9而不是自己设计基于身份的方案——标准化的东西,坑少。

扩展欧几里得算法与大数运算

双线性对的计算离不开大数运算。而扩展欧几里得算法,就是大数运算的基石之一。

扩展欧几里得算法

这个算法能同时求出:

  • 两个数的最大公约数gcd(a, b)
  • 一组整数解x, y,使得ax + by = gcd(a, b)

在SM9中,它主要用于:

  • 计算模逆元
  • 求解中国剩余定理
  • 密钥生成时的参数计算
// 扩展欧几里得算法
function extended_gcd(a, b):
    if b == 0:
        return (a, 1, 0)
    else:
        g, x1, y1 = extended_gcd(b, a % b)
        x = y1
        y = x1 - (a // b) * y1
        return (g, x, y)

大数运算的工程要点

我个人习惯在实现大数运算时,注意以下几点:

  • 使用无符号整数:避免符号位带来的麻烦
  • 注意进位传播:用汇编级的多精度加法
  • 预计算优化:比如Montgomery模乘,能省掉除法

我的经验:在嵌入式设备上实现SM9时,大数运算往往是性能瓶颈。我建议用查表法优化模逆运算,能把速度提升2-3倍。另外,尽量用固定长度的数组,避免动态内存分配。

知识体系总览

下面这张图,把本章的核心知识点串起来了:

双线性对知识体系 双线性对 Weil对 Tate对 Miller算法 n阶点映射 扩域元素 点加倍点 最终幂 SM9应用:密钥封装 / 签名验证 / 密钥交换 底层支撑:扩展欧几里得算法 + 大数运算 核心:双线性对将椭圆曲线上的加法群,映射为乘法群,实现基于身份的密码体制 Tate对 + Miller算法 = SM9的高效实现

从这张图能看出来,双线性对是整个SM9的数学基础。而Miller算法和扩展欧几里得算法,则是把这个数学变成可执行代码的关键。

重要提醒:在实际工程中,千万不要自己实现双线性对。直接用OpenSSL或GMSSL的接口。我曾经见过一个团队自己手写Miller算法,结果在边界条件下出了bug,导致签名验证偶尔失败。这种问题极难排查。

好了,双线性对的内容就讲到这里。记住一句话:双线性对让椭圆曲线从"只能加"变成了"能加能乘",这就是SM9能实现基于身份密码的根本原因。