椭圆曲线的纯量乘法

椭圆曲线点的乘法也称为椭圆曲线的纯量乘法，是将椭圆曲线上的一点反复和自身相加的运算。此运算在椭圆曲线密码学（ECC）中可以用来产生单向函数。
此条目中将这种乘法用标量乘法来表示，再配合。此运算也称为椭圆曲线点的乘法（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"的可能范围很大的话，这在计算上就是不可行的。
点运算.
椭圆曲线上的点，一般会定义三种运算：相加、加倍和反相。
无穷远点.
无穷远点是椭圆曲线算术中的单位元。任意点和此点相加，相加前和相加后的结果不变。若无穷远点加上无穷远点，结果仍为无穷远点。
也就是：
无穷远点也会写成.
反相.
点的反相是指针对某一个点，可以找到另一个点，与其相加后为无穷远点（）。
在椭圆曲线上，一点反相点的"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 = formula_7 #无穷远点
 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"，在资讯安全上，此方法会有的风险。以下的蒙哥马利阶梯（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"可以写成 ""，需要六个点乘二和二个点加运算，"100P"等于"f(P, 100)"。
此一演算法需要执行log2("d")个运算（点乘二或点加）。有许多演算法是以此为基础来进行的修改，例如窗口法、滑动窗口法、NAF、NAF-w、vector chains和蒙哥马利阶梯法。
窗口法.
此演算法的窗口法（windowed version）版本可以选择窗口大小w，再计算所有的formula_8，formula_9。演算法会使用的表示法为formula_10 ，其程式是
 Q ← 0
 for i from m to 0 do
 Q ← point_double_repeat(Q, w)
 if di &gt; 0 then
 Q ← point_add(Q, diP) # using pre-computed value of diP
 return Q
演算法的复杂度和Double-and-add相同，但其点相加使用的较少（实务上，点相加比点加倍要花时间）。一般来说，会选择 "w" 为够小的值，简化预运算的步骤。若针对NIST建议的曲线，一般来说formula_11会是最好的选择。"n"位元整数的复杂度会是formula_12个点加倍，formula_13个点相加。
滑动窗口法.
滑动窗口法（Sliding-window method）会在点相加和点加倍之间取舍，计算的表格类似窗口法，不过只计算formula_8， formula_15。此方式比较有效率，只计算有设定MSB的那些值。而其演算法使用原始double-and-add的表示法formula_16。
 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 &lt; w then
 Perform double-and-add using t 
 return Q
 else 
 Q ← point_double_repeat(Q, w)
 Q ← point_add(Q, tP)
 return Q
此演算法的好处是预运算阶段的复杂程度是一般窗口法的一半，也将较慢的点相加改为点加倍。实务上，使用窗口法而不使用滑动窗口法的情形不太多。此演算法会使用formula_17次点加倍，最多只用formula_18次点加法。
-ary非相邻形式（NAF）方法.
（NAF）的目的是利用点相减的方式和点相加的方式相同的原理，设法使运算量少于滑动窗口法（顶多也只会和滑动窗口法相同）。被乘数formula_19的NAF方式需要先用以下演算法进行计算
 i ← 0
 while (d &gt; 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) &gt;= 2w−1
 return (d mod 2w) − 2w
 else
 return d mod 2w
因此会需要用NAF来进行乘法。此演算法会需要先计算formula_20（其中formula_21是要乘的数）这些点，以及这些点的负值。若是标准的Weierstrass曲线，若formula_22，可得formula_23。因此负值很容易计算。接下来要计算formula_8的乘法：
 Q ← 0
 for j ← i − 1 downto 0 do
 Q ← point_double(Q)
 if (dj != 0)
 Q ← point_add(Q, djP)
 return Q
wNAF方式可以保证平均来说点相加法的密度会是formula_25（比无号的窗口法好一点），其中的预计算会需要一个点加倍及formula_26个点加法。而演算法剩下的部份需要formula_27个点加倍，以及formula_28个点加法。
NAF的一个特性是可以保证每一个非零元素formula_29之后，至少有formula_30个零。其原因是因为演算法在每次计算mods函数后，会清除数字formula_19中，较低的formula_32个位元。在每一个非零元素后面，就会有一定数量的零位元，这些零位元可以不用储存。
已有人发现，若针对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计时攻击，以很低的成本得到完整的私钥。