椭圆曲线的纯量乘法

椭圆曲线点的乘法也称为椭圆曲线的纯量乘法，是将椭圆曲线上的一点反复和自身相加的运算。此运算在椭圆曲线密码学（ECC）中可以用来产生单向函数。
此条目中将这种乘法用标量乘法来表示，再配合Hessian form of an elliptic curve。此运算也称为椭圆曲线点的乘法（elliptic curve point multiplication），不过此名称有时会误解为二个点之间的乘法（其实是整数纯量和点的乘法）。

**基础**
假定在有限域上定义的曲线E（例如E: ），其点乘定义为重复的进行在曲线上点的加法，表示为，其中n是系数（整数）以及在曲线E上的一点，这类的曲线称为魏尔施特拉斯曲线（Weierstrass curve）。
现代椭圆曲线密码学安全性的基础是在给定Q和P，以及的情形下，若n很大，无法求得n的特性而来（类似其他的迪菲-赫尔曼密钥交换问题，此问题称为椭圆曲线离散对数问题）。此原因是因为椭圆曲线上两点的相加（或是某一个点加上自身）会得到第三点，而这个点的位置和前一点或前二点没有明确的关系，重复很多次之后，nP可能会在曲线上的任何位置。在直觉上，椭圆曲线的纯量乘法和以下例子类似：假设在圆上选一个点P，再将其角度加上42.57度，所得的点离P会有一些距离，不过不会太远，不过若加上1000次或1001次的42.57度，需要需比较复杂的运算才能求出所得的点的位置。回到椭圆曲线的纯量乘法，若要进行逆运算，给定Q=nP，已知P和Q，要求n，只能一个一个的针对可能的n来检查，若n的可能范围很大的话，这在计算上就是不可行的。

**点运算**
椭圆曲线的点乘法：相加（图1）、加倍（图2和图4）和反相（图3）
椭圆曲线上的点，一般会定义三种运算：相加、加倍和反相。

**无穷远点**
无穷远点是椭圆曲线算术中的单位元。任意点和此点相加，相加前和相加后的结果不变。若无穷远点加上无穷远点，结果仍为无穷远点。
也就是：

无穷远点也会写成0.

**反相**
点的反相是指针对某一个点，可以找到另一个点，与其相加后为无穷远点（）。

在椭圆曲线上，一点反相点的x座标会和该点相同，而y座标会为该点座标的负值：


**点的相加**
针对二个相异点P和Q，其加法定义为P和Q所形成的直线，和曲线E交点的反相点R.

假设椭圆曲线的方程式是，可以计算得到：

若其中没有任何一点是无穷远点，且这些点的x座标都不同，则上式正确。这在椭圆曲线数字签名算法（ECDSA）上非常重要，因为散列值（hash）有可能为0。

**点的加倍**
假设点P和Q重合（座标相同），其加法类似，但无法依上述方式定义直线，因此使用极限的作法，取曲线E在P点的切线。
计算同上，取导数(dE/dx)/(dE/dy)可得：

其中a是方程式E里的系数。

**点乘法**
最直接计算点乘法的方式就是反复的执行加法。不过也有其他更有效率的算法。

**Double-and-add**
最简单的方式就是double-and-add法，其作法类似模乘幂中的平方求幂。其演算法如下：
要计算sP，要先将s以二进制表示，其中：
以下是迭代演算法，其回圈变数i递减：
let bits = bit_representation #为s的二进制表示（从MSB到LSB）
let res =  #无穷远点
for bit in bits:
res = res + res # double
if bit == 1:            
res = res + P # add
i = i - 1
return res
因Double和add的执行时间不同，根据执行时间就可以知道是执行Double或add，间接可以推算d，在资讯安全上，此方法会有timing attack的风险。以下的蒙哥马利阶梯（Montgomery Ladder）是可以避免计时攻击的作法。
以下则是使用递回函数的作法：
f(P, d) is
if d = 0 then
return 0                         # 已计算完成
else if d = 1 then
return P
else if d mod 2 = 1 then
return point_add(P, f(P, d - 1)) # 若d为奇数，进行addition
else
return f(point_double(P), d/2)   # d为偶数，进行doubling
其中f是乘法的函数，P是要乘的座标，d是要加的次数。例如100P可以写成 nowrap|2(2P + 2(22(P + 2P)))，需要六个点乘二和二个点加运算，100P等于f(P, 100)。
此一演算法需要执行log2(d)个运算（点乘二或点加）。有许多演算法是以此为基础来进行的修改，例如窗口法、滑动窗口法、NAF、NAF-w、vector chains和蒙哥马利阶梯法。

**窗口法**
此演算法的窗口法（windowed version）版本可以选择窗口大小w，再计算所有的，。演算法会使用的表示法为 ，其程式是
Q ← 0
for i from m to 0 do
Q ← point_double_repeat(Q, w)
if di > 0 then
Q ← point_add(Q, diP) # using pre-computed value of diP
return Q
演算法的复杂度和Double-and-add相同，但其点相加使用的较少（实务上，点相加比点加倍要花时间）。一般来说，会选择 w 为够小的值，简化预运算的步骤。若针对NIST建议的曲线，一般来说会是最好的选择。n位元整数的复杂度会是个点加倍，个点相加。

**滑动窗口法**
滑动窗口法（Sliding-window method）会在点相加和点加倍之间取舍，计算的表格类似窗口法，不过只计算， 。此方式比较有效率，只计算有设定MSB的那些值。而其演算法使用原始double-and-add的表示法。
Q ← 0
for i from m downto 0 do
if di = 0 then
Q ← point_double(Q)
else 
t ← extract j (up to w − 1) additional bits from d (including di)
i ← i − j
if j  0) do
if (d mod 2) = 1 then 
di ← d mods 2w
d ← d − di
else
di = 0
d ← d/2
i ← i + 1
return (di−1, di-2, …, d0)
其中有号余数函数mods定义如下

if (d mod 2w) >= 2w−1
return (d mod 2w) − 2w
else
return d mod 2w
因此会需要用NAF来进行乘法。此演算法会需要先计算（其中是要乘的数）这些点，以及这些点的负值。若是标准的Weierstrass曲线，若，可得。因此负值很容易计算。接下来要计算的乘法：
Q ← 0
for j ← i − 1 downto 0 do
Q ← point_double(Q)
if (dj != 0)
Q ← point_add(Q, djP)
return Q
wNAF方式可以保证平均来说点相加法的密度会是（比无号的窗口法好一点），其中的预计算会需要一个点加倍及个点加法。而演算法剩下的部份需要个点加倍，以及个点加法。
NAF的一个特性是可以保证每一个非零元素之后，至少有个零。其原因是因为演算法在每次计算mods函数后，会清除数字中，较低的个位元。在每一个非零元素后面，就会有一定数量的零位元，这些零位元可以不用储存。
已有人发现，若针对OpenSSL进行FLUSH+RELOAD的旁路攻击，约在进行200次签章后，即可以利用cache-timing找到完整私钥。

**蒙哥马利阶梯法**
蒙哥马利阶梯法（Montgomery ladder）会用固定的运算时间来进行点乘法，运算时间只会随d的长度而变化，不会因为d的各位元内容而变化。这可以抵抗旁路攻击中的功率攻击或是计时攻击。此演算法的实现方式和double-and-add相同。
R0 ← 0
R1 ← P
for i from m downto 0 do
if di = 0 then
R1 ← point_add(R0, R1)
R0 ← point_double(R0)
else
R0 ← point_add(R0, R1)
R1 ← point_double(R1)
return R0
此演算法的速度类似double-and-add，但是在处理d的每一位元时，都会进行点相加以及点加倍。因此演算法本身不会因为时间或是功率而泄漏d的资料。
不过若利用旁路攻击中的FLUSH+RELOAD对OpenSSL进行攻击，已证实只需要经由一次签名，用cache计时攻击，以很低的成本得到完整的私钥。