MSM多标量乘法:策略及挑战
1. 引言
在生成 zk-SNARK(zero-knowledge succinct non-interactive argument of knowledge,零知识简洁非交互式知识论证)等操作中,几乎所有的密码学运算都发生在有限域上的椭圆曲线中。
2. 椭圆曲线
椭圆曲线上的一个点是有限域中的一对数 (x,y)(x, y)(x,y),满足方程:
y2=x3+ax+by^2 = x^3 + a x + b y2=x3+ax+b
其中 a,ba, ba,b 是该域中的常数。
可以在椭圆曲线上定义一种“加法”运算,但它不是普通的分量相加 (x1,y1)+(x2,y2)=(x1+x2,y1+y2)(x_1, y_1) + (x_2, y_2) = (x_1 + x_2, y_1 + y_2)(x1,y1)+(x2,y2)=(x1+x2,y1+y2):
- 对于两个不同的点 (x1,y1)(x_1, y_1)(x1,y1) 和 (x2,y2)(x_2, y_2)(x2,y2),它们的和定义为 (x1,y1)+(x2,y2)=(x3,y3)(x_1, y_1) + (x_2, y_2) = (x_3, y_3)(x1,y1)+(x2,y2)=(x3,y3),其中:
s=y2−y1x2−x1x3=s2−x1−x2y3=s(x1−x3)−y1s = \frac{y_2 - y_1}{x_2 - x_1} \\ x_3 = s^2 - x_1 - x_2 \\ y_3 = s(x_1 - x_3) - y_1 s=x2−x1y2−y1x3=s2−x1−x2y3=s(x1−x3)−y1
在这之中有两个例外情况要特别处理:
- 1)当 (x1,y1)=(x2,y2)(x_1, y_1) = (x_2, y_2)(x1,y1)=(x2,y2) 时,加法运算退化为倍点运算(point doubling)。在倍点运算的情况下,其公式为:【其中 aaa 为以上椭圆曲线方程式的系数】
s=3x12+a2y1x3=s2−2x1y3=(x1−x3)−y1s = \frac{3 x_1^2 + a}{2 y_1} \\ x_3 = s^2 - 2 x_1 \\ y_3 = (x_1 - x_3) - y_1 s=2y13x12+ax3=s2−2x1y3=(x1−x3)−y1 - 2)当 x1=x2x_1 = x_2x1=x2 但 y1≠y2y_1 \neq y_2y1=y2 时,这两个点垂直,于是它们的和为无穷远点(记为 O\mathcal{O}O),这是群的零元(加法单位元),对于任意 (x,y)(x,y)(x,y) ,满足:
O+(x,y)=(x,y)\mathcal{O} + (x, y) = (x, y) O+(x,y)=(x,y)
3. 基本运算
在椭圆曲线密码学中,两个基础运算是 点加(point addition) 和 倍点(point doubling),在文中分别称为 ECADD
和 ECDBL
。
如果需要将一点重复加多次(即标量乘法),可以用“倍加加法”(double-and-add)算法,详情可参看2022年8月博客 What every developer needs to know about elliptic curves。
如,要计算 9P9P9P,传统做法是 P+P+⋯+PP + P + \cdots + PP+P+⋯+P 共 8 次加法运算;但用倍加技巧:
P+P=2P2P+2P=4P4P+4P=8P8P+P=9PP + P = 2P \\ 2P + 2P = 4P \\ 4P + 4P = 8P \\ 8P + P = 9P P+P=2P2P+2P=4P4P+4P=8P8P+P=9P
这样总共只用了 4 次加法运算。
当需要计算许多不同点的加和时:
k1P1+k2P2+⋯+knPnk_1 P_1 + k_2 P_2 + \dots + k_n P_n k1P1+k2P2+⋯+knPn
大多数技术都假设这些基本运算(primitives)已经给定,并将重点放在如何执行标量乘法 (k_i P_i) 以及点加法上,从而尽量减少椭圆曲线点加(ECADD)和倍点(ECDBL)运算的次数。
4. 多标量乘法(MSM:Multi-Scalar Multiplication)
多标量乘法是这样的问题:
- 给定一系列标量(即整数 对 某特定素数取模) kik_iki 和椭圆曲线点 Pi=(xi,yi)P_i = (x_i, y_i)Pi=(xi,yi),要计算:
∑i=1nkiPi\sum_{i=1}^n k_i P_i i=1∑nkiPi
在 Aleo 的某个挑战里,n=226n = 2^{26}n=226,也就是说这个操作极其耗时。MSM 是生成 zk-SNARK 证明时最消耗时间的部分之一(约 80% 时间用于 MSM),所以对其优化非常关键。
4.1 分桶法(Bucketing method)
一种常见优化 MSM 的方法是分桶策略(Bucketing method)——可以将多标量乘法(MSM)拆分成更小的求和部分,并通过反复使用windowing窗口化技术来减少运算次数。
如果想要计算每个 kiPik_i P_ikiPi 就可以将其拆分为大小为 ccc 的窗口:
kiPi=ki0Pi+ki12cPi+ki222cPi+⋯+ki,m−12c(m−1)Pik_i P_i = k_{i0} P_i + k_{i1} 2^c P_i + k_{i2} 2^{2c} P_i + \dots + k_{i,m-1} 2^{c (m-1)} P_i kiPi=ki0Pi+ki12cPi+ki222cPi+⋯+ki,m−12c(m−1)Pi
于是整体 MSM 可以重写为:
P=∑ikiPi=∑i∑jkij2cjPiP = \sum_i k_i P_i = \sum_i \sum_j k_{ij} 2^{c j} P_i P=i∑kiPi=i∑j∑kij2cjPi
把求和顺序交换一下:
P=∑j2cj(∑ikijPi)=∑j2cjBjP = \sum_j 2^{c j} \left( \sum_i k_{ij} P_i \right) = \sum_j 2^{c j} B_j P=j∑2cj(i∑kijPi)=j∑2cjBj
换句话说,首先将标量分割成若干个窗口,然后将每个窗口中的所有点合并。现在可以把注意力集中在如何高效地计算每个 BjB_jBj :
Bj=∑ikijPi=∑λ=02c−1λ∑u(λ)PuB_j = \sum_i k_{ij} P_i = \sum_{\lambda=0}^{2^c - 1} \lambda \sum_{u(\lambda)} P_u Bj=i∑kijPi=λ=0∑2c−1λu(λ)∑Pu
这里 ∑u(λ)Pu\sum_{u(\lambda)} P_u∑u(λ)Pu 是把所有系数为 λ\lambdaλ 的点加在一起。
举例: 若 c=3c = 3c=3 且有 15 个点,则
B1=4P1+3P2+5P3+1P4+4P5+6P7+6P8+3P14+5P15=1P4+3(P2+P14)+4(P1+P5)+5(P3+P15)+6(P7+P8)=1S11+3S13+4S14+5S15+6S16B_1 = 4 P_1 + 3 P_2 + 5 P_3 + 1 P_4 + 4 P_5 + 6 P_7 + 6 P_8 + 3 P_{14} + 5 P_{15} \\ = 1 P_4 + 3 (P_2+P_{14}) + 4 (P_1+P_5) + 5(P_3+P_{15}) + 6 (P_7 + P_8) \\ = 1 S_{11} + 3 S_{13} + 4 S_{14} + 5 S_{15} + 6 S_{16}B1=4P1+3P2+5P3+1P4+4P5+6P7+6P8+3P14+5P15=1P4+3(P2+P14)+4(P1+P5)+5(P3+P15)+6(P7+P8)=1S11+3S13+4S14+5S15+6S16
可以按照系数 λ\lambdaλ 来拆分该求和,λ\lambdaλ 取值范围是从 111 到 777:
- 当 λ=1\lambda=1λ=1 时,∑uPu=P4\sum_u P_u = P_4∑uPu=P4(因为 P4P_4P4 是唯一一个系数为 111 的点);
- 当 λ=4\lambda=4λ=4 时,∑uPu=P1+P5\sum_u P_u = P_1 + P_5∑uPu=P1+P5;
- 依此类推。
将所有具有相同系数 λ\lambdaλ 的点放入 λ\lambdaλ-桶(lambda bucket) 中。于是有:
Bj=∑λλSjλ=Sj1+2Sj2+3Sj3+4Sj4+5Sj5+6Sj6+7Sj7B_j = \sum_\lambda \lambda S_{j\lambda} = S_{j1} + 2 S_{j2} + 3 S_{j3} + 4 S_{j4} + 5 S_{j5} + 6 S_{j6} + 7 S_{j7} Bj=λ∑λSjλ=Sj1+2Sj2+3Sj3+4Sj4+5Sj5+6Sj6+7Sj7
可以通过使用部分和(partial sums)来以最少的点加法次数来计算该式:
Tj1=Sj7Tj2=Tj1+Sj6Tj3=Tj2+Sj5Tj4=Tj3+Sj4Tj5=Tj4+Sj3Tj6=Tj5+Sj2Tj7=Tj6+Sj1\begin{aligned} T_{j1} &= S_{j7} \\ T_{j2} &= T_{j1} + S_{j6} \\ T_{j3} &= T_{j2} + S_{j5} \\ T_{j4} &= T_{j3} + S_{j4} \\ T_{j5} &= T_{j4} + S_{j3} \\ T_{j6} &= T_{j5} + S_{j2} \\ T_{j7} &= T_{j6} + S_{j1} \\ \end{aligned} Tj1Tj2Tj3Tj4Tj5Tj6Tj7=Sj7=Tj1+Sj6=Tj2+Sj5=Tj3+Sj4=Tj4+Sj3=Tj5+Sj2=Tj6+Sj1
这些运算中的每一步都只涉及一次椭圆曲线点加法。最后,通过对这些部分和(partial sums)求和来得到最终结果:
Bj=∑kTjkB_j = \sum_k T_{jk} Bj=k∑Tjk
可以通过改变系数 kik_iki 的展开方式来进一步改进该计算。在二进制表示中,汉明重量(Hamming weight) 指的是非零比特的数量。理想情况下,希望这个重量尽可能小,以减少加法次数。
如,在许多实现中,RSA 加密系统的公钥选择为 655376553765537,它等于 216+12^{16} + 1216+1。在 平方-乘法算法(square-and-multiply) 中,只需要进行两次乘法即可完成计算。
二进制表示的平均汉明重量是 1/21/21/2;如果引入带符号的二进制表示(即 −1,0,1-1, 0, 1−1,0,1),则平均重量降低到 1/31/31/3,从而减少平均运算次数。
5. BLS 12-377 曲线
Aleo 使用的曲线是 BLS 12-377,其所在的有限域的素数阶是一个 377 位的素数,具有embedding degree 嵌入度 12。曲线上的群阶(记为 rrr)以及有限域阶 qqq 都具有高度的 2-幂因子结构(即 qqq 和 rrr 都可以写成 2α⋅r+12^\alpha \cdot r + 12α⋅r+1,其中 α>40\alpha > 40α>40)。
Aleo 所使用的曲线称为 BLS12-377。其基域(有限域)的阶为 qqq(一个 377 位的大素数),并且其 嵌入度(embedding degree)为 121212。
椭圆曲线群 G1G_1G1 的阶 rrr 和有限域的阶都具有很强的 2-adic 性质(也就是说,qqq 和 rrr 都可以写成如下形式:
q=2α⋅r+1q = 2^{\alpha} \cdot r + 1 q=2α⋅r+1
其中 rrr 是奇数,并且 α>40\alpha > 40α>40)。
阶 qqq 和 rrr 之间的关系由嵌入度决定:
r∣(q12−1)r \mid (q^{12} - 1) r∣(q12−1)
BLS 12-377 的曲线方程是:
y2=x3+1y^2 = x^3 + 1 y2=x3+1
此外,可以在有限域 FqF_qFq 的二次扩域上构造第二个群 G2G_2G2,对应曲线的方程为:
y2=x3+By^2 = x^3 + B y2=x3+B
其中 BBB 是一个参数。关于该曲线的更多参数信息,可参见ark_bls12_377。
BLS12-377 与 Montgomery 曲线和扭曲 Edwards 曲线(twisted Edwards curve)是双有理等价的(birationally equivalent)。这使得能够通过避免昂贵的域求逆运算,从而更快地进行点加法和标量乘法。在 Montgomery 曲线的情形下,可以在 常数时间(constant time)内完成标量乘法,使得运算对定时攻击(timing attacks)具有抵抗性。
BLS12-377 曲线及其双有理等价的扭曲 Edwards 曲线的实现可在https://github.com/arkworks-rs/curves代码仓库中找到。
BLS12-377 属于 配对友好型(pairing-friendly)椭圆曲线,它们的应用包括:
- 可高效聚合的短数字签名;
- 多项式承诺方案(polynomial commitment schemes);
- 单轮多密钥交换(single-round multi-key exchanges)。
至于为什么 BLS 曲线有两个方程和两个群,这与 双线性配对(pairings)有关。配对是一种双线性映射:
- 它取自两个素数阶 rrr 群的两个点作为输入。
- 出于技术原因,这两个群必须不同。
- 而由于原始曲线只包含一个阶为 rrr 的群,因此需要扩展域来找到其他阶为 rrr 的群。
嵌入度(embedding degree)决定了需要将域扩展多少次才能找到这些额外的群。作为额外的好处,扩展域中包含了所有的 rrr-th 单位根(roots of unity)。
6. 关于扩域(Field Extensions)
嵌入度(embedding degree)也是需要使用的域扩展的次数。熟悉的域扩展示例包括:
- 实数域 R\mathbb{R}R(是有理数域 Q\mathbb{Q}Q 的扩展),
- 复数域 C\mathbb{C}C(扩展了 R\mathbb{R}R)。
- 复数域不能再进一步扩展,因为在 C\mathbb{C}C 中不存在不可约多项式(称复数是代数闭合的)。
如果要构造有限域 Fq\mathbb{F}_qFq 的二次扩域 Fq2\mathbb{F}_{q^2}Fq2,可以将其表示为一个多项式:
a0+a1xa_0 + a_1 x a0+a1x
其中 a0,a1∈Fqa_0, a_1 \in \mathbb{F}_qa0,a1∈Fq。
- 加法 很直接,只需分别相加常数项和一阶项。
- 乘法:设有两个元素 aaa 和 bbb:
a×b=a0b0+(a0b1+a1b0)x+a1b1x2a \times b = a_0 b_0 + (a_0 b_1 + a_1 b_0) x + a_1 b_1 x^2 a×b=a0b0+(a0b1+a1b0)x+a1b1x2
为了避免结果超出一阶多项式的范围,可以通过一个不可约多项式来约简,如选择:
x2+1=0x^2 + 1 = 0 x2+1=0
代入后,有:
a×b=a0b0−a1b1+(a0b1+a1b0)xa \times b = a_0 b_0 - a_1 b_1 + (a_0 b_1 + a_1 b_0) x a×b=a0b0−a1b1+(a0b1+a1b0)x
这与复数的乘法非常相似。
选择不可约多项式的条件:
- 1)它的阶数必须与扩域的阶数一致(这里是二阶)。
- 2)它必须在扩展的基础域上不可约,即不能再分解为更低阶多项式。
在 Fq12\mathbb{F}_{q^{12}}Fq12 中的运算既复杂又昂贵。幸运的是,可以使用 六次扭曲(sextic twist),使得群 G2G_2G2 可以定义在较小的扩域 Fq2\mathbb{F}_{q^2}Fq2 上。
在实际应用中,当我们需要构造类似 Fq12\mathbb{F}_{q^{12}}Fq12 这样的扩域时,可以通过逐步扩展较小的域来实现,即 扩域塔(tower of extensions) 的形式,如:
Q→R→C\mathbb{Q} \rightarrow \mathbb{R} \rightarrow \mathbb{C} Q→R→C
这种方式就是把高阶扩域分解为多个低阶扩域,逐层构建。
7. 更快的方式:FFT
在实现 ECADD(椭圆曲线点加) 和 ECDBL(倍点) 时,可能会用到 FFT。可以在不同的坐标系下进行这些运算。正如Need for speed: Elliptic curves chapter已有研究指出的,射影坐标(projective coordinates) 通常更快,因为它避免了有限域求逆(求逆远比乘法和加法昂贵得多)。
当使用射影坐标时,运算更快的原因是们用乘法替代了除法。但这也意味着需要进行大量的乘法,因此需要高效的整数乘法算法,如:
- Karatsuba 算法
- Toom-Cook 算法
- FFT 算法
由于涉及大整数的乘法,具体使用哪种算法取决于这些整数的大小。更多详情参看博客 Weird ways to multiply really fast with Karatsuba, Toom–Cook and Fourier
参考资料
[1] LambdaClass团队2023年1月9日博客 Multiscalar Multiplication: Strategies and Challenges
[2] 2024年6月drouyang hackmd Pippenger Algorithm for Multi-Scalar Multiplication (MSM)