椭圆加密算法(ECC)是一种公钥加密体制,最初由Koblitz和Miller两人于1985年提出,其数学基础是利用椭圆曲线上的有理点构成Abel加法群上椭圆离散对数的计算困难性。公钥密码体制根据其所依据的难题一般分为三类:大素数分解问题类、离散对数问题类、椭圆曲线类。有时也把椭圆曲线类归为离散对数类。
之所以称其为椭圆曲线加密,是因为这种加密方式是在椭圆曲线方程上进行操作。即形如
的方程。由于在标准的椭圆曲线方程上进行运算会出现小数或者无理数,从而导致精度的问题,所以我们通过取模,将椭圆曲线上的点变成整数点,并构成一个封闭群,便于后续运算。即变形成
的形式,其中p一般取一个大素数。
椭圆曲线也可以有运算,像实数的加减乘除一样,这就需要使用到加群。19世纪挪威的尼尔斯·阿贝尔抽象出了加群(又叫阿贝尔群或交换群)。数学中的群是一个集合,我们为它定义了一个“加法”,并用符号+表示,遵循以下四个特性:
- 封闭性:如果a和b都是封闭群的成员,那么a+b也是封闭群的成员;
- 结合律:(a + b) + c = a + (b + c);
- 单位元:a+0=0+a=a,0就是封闭群的单位元;
- 逆元:对于任意值a必定存在b,使得a+b=0。
如果再增加一个条件,交换律:a + b = b + a,则称这个群为阿贝尔群,根据这个定义整数集是个阿贝尔群。
在椭圆曲线上,加法的运算定义如图1所示:过曲线上的两点A、B画一条直线,找到直线与椭圆曲线的交点,交点关于x轴对称位置的点,定义为A+B,即为加法。如下图所示:A + B = C
图1 椭圆曲线加法运算
不妨举一个例子,假设椭圆曲线的方程为
,设点A的坐标为(2,3),点B的坐标为(0,1),那么直线AB的方程为y=x+1,代入方程可知
,于是可很快求出第三个交点C的坐标(-1,0),也就是C=A+B。当然,这里C也满足C=B+A,所以椭圆曲线群是一个阿贝尔群。
图2 椭圆曲线加法运算
根据这个定义,我们来讨论一下一般情形下椭圆曲线的加法运算公式,假设椭圆曲线的方程为
,设A的坐标为(x1,y1),B的坐标为(x2,y2),那么直线AB的方程为
。带入椭圆曲线的方程,有
,根据韦达定理,如果设直线AB与椭圆曲线的第三个交点为 (x3,y3),那么就有
,所以
,由于最后还要将第三个交点的坐标关于x轴翻折一下,所以如果设C=A+B,那么C的坐标为:
特别的,如果计算出来的C的坐标是一个分数,也就是形如
的形式。那么
的求法如下:由于
,设
,那么1≡nb(modp)由费马小定理:如果p是一个质数,而整数a不是p的倍数,则有
。带入上述式子可知,
。所以
这边再举一个例子,设椭圆曲线方程为
,A坐标为(4,4),B坐标为(0,1),那么根据公式
,再根据上述分数取模的算法得到C=(33,14)。特别的,当A和B的坐标相等时,也就是A=B时,C=A+A,这个时候为了书写方便,可写为C=2A,乘法的计算就诞生了,如果要计算3A,4A或者更高的数nA时,只需要转化成加法,将n个A依次按照加法运算即可。这时候直线的斜率k就是该点的切线斜率,也就是
。举个例子:假设椭圆曲线的方程为y2≡x3+1(mod11),设点A的坐标是(2,3),那么k=2,切线方程为y=2x-1,带入公式求出2A的坐标(0,1)。
图3 椭圆曲线乘法运算
椭圆曲线加密的原理就是利用C=nA的乘法运算时,知道n和A可以很快求出C,但是知道C和A很难求出n的值,下面来看一下椭圆曲线加密的具体流程。
首先定义如下概念:
基点P:指的是椭圆曲线上满足方程的任意一点,该点会公开。
私钥k:私钥k是一个大整数,该数由发送方和接收方私自保存,不公开。
公钥Q:公钥的计算法则是将私钥k和基点P相乘,做为Q,也就是Q=kP,公钥也会公开。
明文M:这里的明文M是一个点,假设我们要将一个数m进行加密,那么就需要计算出满足
的椭圆方程的一个y值构成点(m,y)。那么明文M的值就是(m,y),这个明文不公开。
加密法则E(M):加密法则如下,我们先随机选择一个随机数r,那么就可以得到密文c,c= E(M)=(rP,M+rQ),密文c是一个点对,密文c会公开。
解密法则D(c):解密法则如下,M=D(c)= M+rQ-krP。
举个例子:
假设椭圆曲线方程为
,发送方和接收方选取的私钥k=7,基点P为(0,1),假设发送方想要把一个数4发送给接收方,那么先将x=4带入曲线方程,得到明文M(4,4)。再根据k和P计算出公钥Q=7P=(42, 14),随机选一个数r=3,那么密文c= E(M)=(rP,M+rQ)=((19, 28), (6, 45))。
接收方知道了密文c和私钥k,只需要按照解密法则M=D(c)= M+rQ-krP就可以求出明文M(4,4)。
python代码如下:
#coding:gbk
p = 53
i = lambda x: pow(x, p-2, p)
def add(A, B):#加法运算
(u, v), (w, x) = A, B
assert u != w or v == x
if u == w: m = (3*u*w + 1) * i(v+x)
else: m = (x-v) * i(w-u)
y = m*m - u - w
z = m*(u-y) - v
return y % p, z % p
def opposite(A):#取A的相反数,也就是将A变成-A
return A[0],(-A[1])%p
def mul(t, A, B=0):#乘法运算
if not t:
return B
if t%2==0:
return mul(t//2, add(A,A), B)
elif B!=0:
return mul(t//2, add(A,A), add(B,A))
else:
return mul(t//2, add(A,A),A)
M=(4,4)
P=(0,1)
r=3
k=7
Q=mul(k,P)
c=(mul(r,P),add(M,mul(r,Q)))
print("公钥Q是",Q)
print("密文c是",c)
print("明文M是",add(c[1],opposite(mul(k,c[0]))))
在CTF中,ECC加密是一种较为常见的题型,例如:攻防世界 (xctf.org.cn)
图4 题目描述
题目告诉了基点,私钥以及椭圆曲线的方程,让我们求公钥,python代码如下:
#coding:gbk
p = 15424654874903
a = 16546484
i = lambda x: pow(x, p-2, p)
def add(A, B):#加法运算
(u, v), (w, x) = A, B
assert u != w or v == x
if u == w: m = (3*u*w + a) * i(v+x)
else: m = (x-v) * i(w-u)
y = m*m - u - w
z = m*(u-y) - v
return y % p, z % p
def opposite(A):#取A的相反数,也就是将A变成-A
return A[0],(-A[1])%p
def mul(t, A, B=0):#乘法运算
if not t:
return B
if t%2==0:
return mul(t//2, add(A,A), B)
elif B!=0:
return mul(t//2, add(A,A), add(B,A))
else:
return mul(t//2, add(A,A),A)
G=(6478678675,5636379357093)
k=546768
K=mul(k,G)
print("公钥K是",K)#公钥K是 (13957031351290, 5520194834100)