考虑使用 P+Q ← xADD(P, Q, P-Q) 和 [2]P ← xDBL(P) 实现 [m]P + [n]Q 的常数时间双并行计算。
我们可以将 m 和 n 分解成二进制形式:
[m]P+[n]Q=[i=0∑k−1b0,i2i]P+[i=0∑k−1b1,i2i]Q
根据二分法的经典思路,我们可以写出递归式:
R0(i)=2R0(i+1)+b0,iP+b1,iQ
其中,初始状态 R0(k)=O,R0(i)=[j=i∑k−1b0,j2j−i]P+[j=i∑k−1b1,j2j−i]Q。
不过值得注意的是:这种基础算法不仅容易受到侧信道攻击(执行时间取决于比特位是 0 还是 1),而且无法使用高效的蒙哥马利 xADD,因为 xADD 要求在计算 A+B 时,必须已知 A−B 的值。
这时我们将偏差记成一个预存的常量 D(i)=b0,iP+b1,iQ,这样就有:
R0(i)=2R0(i+1)+D(i)←xADD(R0(i+1),R0(i+1)+D(i),D(i))
记 R∗(i)=R0(i)+D(i)。
所有 R∗(i) 可能的值就恰好构成了一个差分矩形:
$R_0^{(i)}$
$R_0^{(i)} + P$
$R_0^{(i)} + Q$
$R_0^{(i)} + P + Q$
但是问题来了:我们需要预先计算出 D(i) 的值,而 D(i) 的值又依赖于 b0,i 和 b1,i 的值,这是变化的。不过我们注意到,他们的变化范围是有限的,于是我们可以利用打表的方式,即预先计算出 D(i) 的所有可能取值。
P 和 Q 的值我们总是清楚的,D(i) 的值也只有 4 种可能:{0,P,Q,P+Q}。且根据 xADD 的方法,当我们知道 {P,Q,P+Q,P−Q} 中任意三个点的值时,我们总能构造出第四个值。
如果我们允许用四个寄存器来存储上述差分矩形的基点,那么算法会变得十分清楚。
设:
⎩⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎧R0(i)=R0(i)R1(i)=R0(i)+PR2(i)=R0(i)+QR3(i)=R0(i)+P+Q
与此同时,将上述构造出来的四个点打包成一个整体的状态:
S(i)=⎝⎜⎜⎜⎜⎛R0(i)R1(i)R2(i)R3(i)⎠⎟⎟⎟⎟⎞
根据递归式,我们可以得到如下运算表格:
| b0,i |
b1,i |
R0(i−1) |
R1(i−1) |
R2(i−1) |
R3(i−1) |
| 0 |
0 |
2R0(i) |
R0(i)+R1(i) |
R0(i)+R2(i) |
R0(i)+R3(i) |
| 1 |
0 |
R1(i)+R0(i) |
2R1(i) |
R1(i)+R2(i) |
R1(i)+R3(i) |
| 0 |
1 |
R2(i)+R0(i) |
R2(i)+R1(i) |
2R2(i) |
R2(i)+R3(i) |
| 1 |
1 |
R3(i)+R0(i) |
R3(i)+R1(i) |
R3(i)+R2(i) |
2R3(i) |
下面用函数式的方式重述算法。
注意到上述表格告诉我们,每一行都会恰好有一个 xDBL 和 三个 xADD,为了尽量做到常数时间,我们固定主要运算函数:
f(T0,T1,T2,T3,D1,D2,D3)=⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧T0←xDBL(T0)T1←xADD(T0,T1,D1)T2←xADD(T0,T2,D2)T3←xADD(T0,T3,D3)=(2T0,T0+T1,T0+T2,T0+T3,∗)
为了完整描述算法过程,我们定义置换函数:
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧π0=idπ1:(R0,R1,R2,R3,∗)↦(R1,R0,R2,R3,∗)π2:(R0,R1,R2,R3,∗)↦(R2,R1,R0,R3,∗)π3:(R0,R1,R2,R3,∗)↦(R3,R1,R2,R0,∗)
不难发现上述置换事实上均为对换,即具有对合性。
设初始状态(未开始迭代的状态)为 S(k)=(O,P,Q,P+Q)t,标量位组合索引序列为 βi=b0,i+2b1,i。下面考虑将 S(k)→S(0) 进行全路径展开。
根据单步状态转移方程:
S(i)=πβi(f(πβi(S(i+1)),Δβi))
其中,Δβi=(D1,D2,D3) 是传给 xADD 的差值常量组。因为 Montgomery 曲线上的 xADD 仅依赖于差值的仿射 x 坐标(即 x(A−B)=x(B−A),符号免疫),我们可以通过预计算得出所有可能的 Δβ。
具体来说,Δβ 恰好是点集 {0,P,Q,P+Q} 在经过 πβ 置换后,第 1、2、3 项与第 0 项的差值:
- β=0:Δ0=(P,Q,P+Q)
- β=1:Δ1=(P,P−Q,Q)
- β=2:Δ2=(P−Q,Q,P)
- β=3:Δ3=(Q,P,P+Q)
这意味着我们还需要四个寄存器预存储预计算的四个差点: P,Q,P+Q,P−Q。
将全过程从 S(k) 向 S(0) 逐层嵌套展开:
S(k−1)S(k−2)S(0)=πβk−1∘f∘πβk−1(S(k))=πβk−2∘f∘πβk−2∘πβk−1∘f∘πβk−1(S(k))⋮=πβ0∘f∘πβ0∘πβ1∘f∘πβ1∘⋯∘πβk−2∘πβk−1∘f∘πβk−1(S(k))
仔细观察 S(0) 的表达式,发现除了最外层和最内层的置换,中间所有的置换全部两两相邻,形成了 πβi∘πβi+1 的形式。
之前定义的 π 函数(例如 π1 仅仅对换了 R0 和 R1,而保持 R2,R3 不变)在数学上是一个局部对换,它们不满足封闭性。
比如 π1∘π2 会产生一个三阶循环轮换((0,1,2,3)↦(1,2,0,3)),它既不是对合的,也无法用单一的 πx 来表示。如果沿用这个定义,我们举步维艰,接下来我们必须将 π 置换升级为全局异或置换
将基点状态 S 的四个位置索引看作两位二进制数 x∈{00,01,10,11}2。重新定义置换群 Π={π0,π1,π2,π3},使其作用在状态 S 上的规则为索引的按位异或:
πj(Rx)=Rx⊕j
展开来看,四个置换的完整映射为:
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧π0:(R0,R1,R2,R3)↦(R0,R1,R2,R3)π1:(R0,R1,R2,R3)↦(R1,R0,R3,R2)(不仅换 0,1,还换 2,3)π2:(R0,R1,R2,R3)↦(R2,R3,R0,R1)π3:(R0,R1,R2,R3)↦(R3,R2,R1,R0)
即使 π1 同时交换了 R2 和 R3,经过固定的 f 函数计算后,再用 π1 换回来,结果依然完美符合上述运算表格(因为 f 中的加法操作是关于 T0 的,且差值 Δ 也经过了对应的预排列)。值得一提的是,升级为异或置换后,群 Π 同构于 Klein 四元群 V4,满足复合律:
πa∘πb=πa⊕b
定义索引序列 β 的布尔差分导数序列 r:
ri=∂i∂β≡βi⊕βi+1i∈{0,1,…,k−2}
注:为了形式统一,我们可以假定一个虚拟的初始前置状态 βk=0,使得 rk−1=βk−1⊕0=βk−1。
利用 Klein 四元群的复合律 πa∘πb=πa⊕b,我们将所有相邻的置换合并:
πβi∘πβi+1=πβi⊕βi+1=πri
将 ri 代入展开式中,就有:
S(0)=πβ0∘f∘πr0∘f∘πr1∘f∘⋯∘πrk−2∘f∘πrk−1(S(k))
这样构造出来的常数时间算法,实际上是再执行这样一条流水线:
状态装载πdk−1计算fπdk−2计算f⋯πd0计算fπβ0还原目标结果
这样的方法只关注当前步和上一步的状态差异,将置换次数减半,同时差分导数只会最多泄露标量位之间的相对消息,具有天然的抗测信道攻击的能力。
最后写出伪代码如下所示:
\begin{algorithm}
\caption{Constant-Time 2-D Montgomery Ladder (4 Registers, Baby)}
\begin{algorithmic}
\Require $k$-bit scalars $m = \sum b_{0,i}2^i, n = \sum b_{1,i}2^i$, Base points $P, Q, P+Q, P-Q$
\Ensure Return point $R = [m]P + [n]Q$
\State \Comment{Phase 1: Precompute Difference Table $\Delta$}
\State $\Delta_0 \gets (P, Q, P+Q)$
\State $\Delta_1 \gets (P, P-Q, Q)$
\State $\Delta_2 \gets (P-Q, Q, P)$
\State $\Delta_3 \gets (Q, P, P+Q)$
\State \Comment{Phase 2: Initialization}
\State $(R_0, R_1, R_2, R_3) \gets (\mathcal{O}, P, Q, P+Q)$
\State $\beta_{prev} \gets 0$
\State \Comment{Phase 3: Main Evaluation Loop}
\For{$i = k-1$ \textbf{downto} $0$}
\State $\beta_i \gets b_{0,i} + 2 \cdot b_{1,i}$
\State $r_i \gets \beta_i \oplus \beta_{prev}$ \Comment{Boolean differential derivative}
\State \Comment{Apply $\pi_{r_i}$ using orthogonal Constant-Time Swaps (CSWAP)}
\State $v_0 \gets r_i \text{ AND } 1$
\State $v_1 \gets (r_i \text{ AND } 2) \gg 1$
\State $\texttt{CSWAP}(v_0, R_0, R_1)$
\State $\texttt{CSWAP}(v_0, R_2, R_3)$
\State $\texttt{CSWAP}(v_1, R_0, R_2)$
\State $\texttt{CSWAP}(v_1, R_1, R_3)$
\State \Comment{Execute fixed function $f$}
\State $T_0 \gets \texttt{xDBL}(R_0)$
\State $T_1 \gets \texttt{xADD}(R_0, R_1, \Delta_{\beta_i}[0])$
\State $T_2 \gets \texttt{xADD}(R_0, R_2, \Delta_{\beta_i}[1])$
\State $T_3 \gets \texttt{xADD}(R_0, R_3, \Delta_{\beta_i}[2])$
\State $(R_0, R_1, R_2, R_3) \gets (T_0, T_1, T_2, T_3)$
\State $\beta_{prev} \gets \beta_i$
\EndFor
\State \Comment{Phase 4: Final Restore Permutation $\pi_{\beta_0}$}\State $v_0 \gets \beta_{prev} \text{ AND } 1$
\State $v_1 \gets (\beta_{prev} \text{ AND } 2) \gg 1$
\State $\texttt{CSWAP}(v_0, R_0, R_1)$
\State $\texttt{CSWAP}(v_0, R_2, R_3)$
\State $\texttt{CSWAP}(v_1, R_0, R_2)$
\State $\texttt{CSWAP}(v_1, R_1, R_3)$
\State \Return $R_0$
\end{algorithmic}
\end{algorithm}
可以看到,上述伪代码中所构造出的差分表所体现的对存储空间的需求略显臃肿,这是因为上文中列出的 Δβ 差分表,其实依然是基于旧的“局部对换”法则得出的结果。如果我们严格按照全局异或置换 πj(Rx)=Rx⊕j 来重新推导,稍后我们就会发现,几乎不需要复杂的动态加载。
在每一步迭代中,f 函数执行的核心操作是:
Tx←xADD(T0,Tx,Dx)for x∈{1,2,3}
由于状态 S 经过了 πβ 的置换,我们有 Tx=Sβ⊕x 和 T0=Sβ。因此,f 函数所需要的差值必然是:
Dx=Tx−T0=Sβ⊕x−Sβ
我们将四个基点用二进制索引 y=y1y0∈{00,01,10,11}2 统一表示:
Sy=y0P+y1Q
代入差值公式:
Dx=((β⊕x)0P+(β⊕x)1Q)−(β0P+β1Q)
Dx=((β0⊕x0)−β0)P+((β1⊕x1)−β1)Q
利用布尔代数的一个小技巧 (b⊕a)−b=(−1)ba,上式可以直接化简为:
Dx=(−1)β0x0P+(−1)β1x1Q
由于 Montgomery 曲线上的 xADD 具有符号免疫性(仅依赖仿射 x 坐标,即 A−B≡B−A),我们在传入差点时可以取绝对值。
下面分别来看 x=1,2,3 时的 Dx:
- 对于 T1 (x=1⟹x0=1,x1=0):D1=(−1)β0P≡P (永远是 P,与 β 无关)
- 对于 T2 (x=2⟹x0=0,x1=1):D2=(−1)β1Q≡Q (永远是 Q,与 β 无关)
- 对于 T3 (x=3⟹x0=1,x1=1):D3=(−1)β0P+(−1)β1Q
- 如果 β0=β1(即 β∈{0,3}),D3=±(P+Q)≡P+Q。
- 如果 β0=β1(即 β∈{1,2}),D3=±(P−Q)≡P−Q。
综上所述:在全局异或置换下,真正的差分表 Δβ 应该是:
- Δ0=(P,Q,P+Q)
- Δ1=(P,Q,P−Q)
- Δ2=(P,Q,P−Q)
- Δ3=(P,Q,P+Q)
通过上述推导可以发现,我们只需要让 D1 和 D2 是绝对的静态常量 P 和 Q,然后动态传递 T3 的差值(在 P+Q 和 P−Q 之间横跳)。下面用 F1,F2 分别存储 P+Q 和 P−Q。
定义状态变量 ci=b0,i⊕b1,i,于是不难讨论得到:
- 当 ci=0 时,我们需要 T3 的差值为 P+Q;
- 当 ci=1 时,我们需要 T3 的差值为 P−Q。
据此,给出优化后的伪代码如下:
\begin{algorithm}
\caption{Optimized Constant-Time 2-D Montgomery Ladder (4 Registers, Dynamic Diff)}
\begin{algorithmic}
\Require $k$-bit scalars $m = \sum b_{0,i}2^i, n = \sum b_{1,i}2^i$, Base points $P, Q, P+Q, P-Q$
\Ensure Return point $R = [m]P + [n]Q$
\State \Comment{Phase 1: Dynamic Difference Initialization}
\State $D_1 \gets P$
\State $D_2 \gets Q$
\State $F_1 \gets P+Q$
\State $F_2 \gets P-Q$
\State $c_{prev} \gets 0$ \Comment{Tracks the XOR state of scalar bits}
\State \Comment{Phase 2: Point Initialization}
\State $(R_0, R_1, R_2, R_3) \gets (\mathcal{O}, P, Q, P+Q)$
\State $\beta_{prev} \gets 0$
\State \Comment{Phase 3: Main Evaluation Loop}
\For{$i = k-1$ \textbf{downto} $0$}
\State $\beta_i \gets b_{0,i} + 2 \cdot b_{1,i}$
\State $r_i \gets \beta_i \oplus \beta_{prev}$ \Comment{Boolean differential derivative}
\State \Comment{Apply $\pi_{r_i}$ using orthogonal Constant-Time Swaps}
\State $v_0 \gets r_i \text{ AND } 1$
\State $v_1 \gets (r_i \text{ AND } 2) \gg 1$
\State $\texttt{CSWAP}(v_0, R_0, R_1)$
\State $\texttt{CSWAP}(v_0, R_2, R_3)$
\State $\texttt{CSWAP}(v_1, R_0, R_2)$
\State $\texttt{CSWAP}(v_1, R_1, R_3)$
\State \Comment{Dynamic Difference Loading for $T_3$}
\State $c_i \gets b_{0,i} \oplus b_{1,i}$
\State $swap\_diff \gets c_i \oplus c_{prev}$
\State $\texttt{CSWAP}(swap\_diff, F_1, F_2)$
\State \Comment{Execute fixed function $f$}
\State $T_0 \gets \texttt{xDBL}(R_0)$
\State $T_1 \gets \texttt{xADD}(R_0, R_1, D_1)$
\State $T_2 \gets \texttt{xADD}(R_0, R_2, D_2)$
\State $T_3 \gets \texttt{xADD}(R_0, R_3, F_1)$
\State $(R_0, R_1, R_2, R_3) \gets (T_0, T_1, T_2, T_3)$
\State $\beta_{prev} \gets \beta_i$
\State $c_{prev} \gets c_i$
\EndFor
\State \Comment{Phase 4: Final Restore Permutation $\pi_{\beta_0}$}
\State $v_0 \gets \beta_{prev} \text{ AND } 1$
\State $v_1 \gets (\beta_{prev} \text{ AND } 2) \gg 1$
\State $\texttt{CSWAP}(v_0, R_0, R_1)$
\State $\texttt{CSWAP}(v_0, R_2, R_3)$
\State $\texttt{CSWAP}(v_1, R_0, R_2)$
\State $\texttt{CSWAP}(v_1, R_1, R_3)$
\State \Return $R_0$
\end{algorithmic}
\end{algorithm}
那么问题来了,我们是否可以考虑用三个寄存器存储基点(R0(i),R1(i),R2(i))达到目的呢?
设:
{R1(i)=R0(i)+D(i)R2(i)=R0(i)+F(i)
与此同时,将上述构造出来的三个点打包成一个整体的状态:
S(i)=⎝⎜⎜⎛R0(i)R1(i)R2(i)⎠⎟⎟⎞
这时的 S(i) 在同构意义上就恰好有三种取法:
| D(i) |
F(i) |
R0(i) |
R1(i) |
R2(i) |
| P |
Q |
R0(i) |
R0(i)+P |
R0(i)+Q |
| P |
P+Q |
R0(i) |
R0(i)+P |
R0(i)+P+Q |
| Q |
P+Q |
R0(i) |
R0(i)+Q |
R0(i)+P+Q |
体现在差分矩形上即下图所示:
$R_0^{(i)}$
$R_1^{(i)}$
$R_2^{(i)}$
(a) $D^{(i)} = P, F^{(i)} = Q$
$R_0^{(i)}$
$R_1^{(i)}$
$R_2^{(i)}$
(b) $D^{(i)} = P, F^{(i)} = P + Q$
$R_0^{(i)}$
$R_1^{(i)}$
$R_2^{(i)}$
(c) $D^{(i)} = Q, F^{(i)} = P + Q$
基于当下的这个状态,我们继续往后推导。接下来我们需要关注的就是两件事:
- 在上述三种情况下,我对下一状态能够使用
xDBL 和 xADD 组合出多少结果;
- 对于下一个状态我们需要的是哪些结果
我们需要对照这两件事是否兼容。
- 第一种情况:D(i)=P,F(i)=Q,下一个状态 S(i−1) 的四种计算情况为:
| b0,i |
b1,i |
R0(i−1) |
R1(i−1) |
R2(i−1) |
| 0 |
0 |
2R0(i) |
R0(i)+R1(i) |
R0(i)+R2(i) |
| 1 |
0 |
R0(i)+R1(i) |
2R1(i) |
R1(i)+R2(i) |
| 0 |
1 |
R0(i)+R2(i) |
R1(i)+R2(i) |
2R2(i) |
| 1 |
1 |
R1(i)+R2(i) |
2R1(i)+Q |
2R2(i)+P |
$R_0^{(i)}$
$R_1^{(i)}$
$R_2^{(i)}$
$D^{(i)} = P, F^{(i)} = Q$
→
$2R_0^{(i)}$
$R_0^{(i)}+R_1^{(i)}$
$2R_1^{(i)}$
$R_0^{(i)}+R_2^{(i)}$
$R_1^{(i)}+R_2^{(i)}$
$2R_1^{(i)}+Q$
$2R_2^{(i)}$
$2R_2^{(i)}+P$
$2R_2^{(i)}+2P$
其中 b0,i=1,b1,i=1 情况下,我们无法直接通过已有的变量得到 2R1(i)+Q 和 2R2(i)+P。
- 第二种情况:D(i)=P,F(i)=P+Q,下一个状态 S(i−1) 的四种计算情况为:
| b0,i |
b1,i |
R0(i−1) |
R1(i−1) |
R2(i−1) |
| 0 |
0 |
2R0(i) |
R0(i)+R1(i) |
R0(i)+R2(i) |
| 1 |
0 |
R0(i)+R1(i) |
2R1(i) |
R1(i)+R2(i) |
| 0 |
1 |
R0(i)+R2(i)+P |
R0(i)+R2(i) |
R0(i)+R2(i)+Q |
| 1 |
1 |
R0(i)+R2(i) |
R1(i)+R2(i) |
2R2(i) |
$R_0^{(i)}$
$R_1^{(i)}$
$R_2^{(i)}$
$D^{(i)} = P, F^{(i)} = P + Q$
→
$2R_0^{(i)}$
$R_0^{(i)}+R_1^{(i)}$
$2R_1^{(i)}$
$2R_0^{(i)}+Q$
$R_0^{(i)}+R_2^{(i)}$
$R_1^{(i)}+R_2^{(i)}$
$2R_0^{(i)}+2Q$
$R_1^{(i)}+R_2^{(i)}+Q$
$2R_2^{(i)}$
其中 b0,i=0,b1,i=1 情况下,我们无法直接通过已有的变量得到 R1(i)+R2(i)+Q 和 2R0(i)+Q。
- 第三种情况:D(i)=Q,F(i)=P+Q,下一个状态 S(i−1) 的四种计算情况为:
| b0,i |
b1,i |
R0(i−1) |
R1(i−1) |
R2(i−1) |
| 0 |
0 |
2R0(i) |
R0(i)+R1(i) |
R0(i)+R2(i) |
| 1 |
0 |
2R0(i)+P |
R0(i)+R2(i) |
R1(i)+R2(i)+P |
| 0 |
1 |
R0(i)+R2(i) |
2R1(i) |
R1(i)+R2(i) |
| 1 |
1 |
R0(i)+R2(i) |
R1(i)+R2(i) |
2R2(i) |
$R_0^{(i)}$
$R_1^{(i)}$
$R_2^{(i)}$
$D^{(i)} = Q, F^{(i)} = P + Q$
→
$2R_0^{(i)}$
$2R_0^{(i)}+P$
$2R_0^{(i)}+2P$
$R_0^{(i)} + R_1^{(i)}$
$R_0^{(i)}+R_2^{(i)}$
$R_1^{(i)}+R_2^{(i)}+P$
$2R_1^{(i)}$
$R_1^{(i)}+R_2^{(i)}$
$2R_2^{(i)}$
其中 b0,i=1,b1,i=0 情况下,我们无法直接通过已有的变量得到 R1(i)+R2(i)+P 和 2R0(i)+P。
我们发现,不幸的是,在上述三种情况下,我们总有一种输入比特的组合 (b0,i,b1,i),使得我们无法通过已有的变量通过 xDBL 和 xADD 得到对应的下一个状态。
这时,我们又该怎么办?
如果可以把 D(i)=P,F(i)=P+Q 和 D(i)=Q,F(i)=P+Q 这两种情况拼在一起,那么是不是就可以通过 xDBL 和 xADD 得到所有的下一个状态了?