作者:Andrea Corbellini
翻译:Hantao Sun
这是椭圆曲线密码学系列的第二篇文章
椭圆曲线密码学系列文章链接:
在上一篇文章中,我们知道椭圆曲线如何在实数域上定义群。尤其是定义了点的加法法则:给定三个共线的点,它们的和等于0(P+Q+R=0)。并且推导出计算点加法的几何方法和代数方法。
下面我们介绍一下数乘(nP=P+P+⋯+P) ,并且给出了一个“简单”算法:倍数相加
现在,我们要将实数域上的椭圆曲线限制在有限域上,看看有什么变化。
模p的有限域
有限域首先是有限数字的集合。例如:模p的有限域,p必须是素数(以下“素数域”等同于”有限域”),它通常表示为Z/p,GF(p)或者Fp,我们使用后者来标记。
在Fp中有两个二元操作符加法(+)和乘法(⋅),他们是封闭的、满足交换律和结合律。对于这两个操作符,都存在一个唯一的元素和逆元素。最后,乘法对加法满足分配律:x⋅(y+z)=x⋅y+x⋅z。
模P的整数集合由0到p−1的所有整数组成。加法和乘法都需要进行模运算(也称作“时钟算术”)。下面是关于F23的例子:
- 加法:(18+9)mod23=4
- 减法:(7−14)mod23=16
- 乘法:4⋅7mod23=5
- 加法逆元:−5mod23=18
算法:(5+(−5))mod23=(5+18)mod23=0 - 乘法逆元:9−1mod23=18
算法:9⋅9−1mod23=9⋅18mod23=1
如果您不熟悉这些公式,可以通过可汗学院来获取模运算的相关知识。
我们之前说过,模p的整数是个域,可以满足上面的所有公式。请注意,p必须是一个素数。模4的整数集合不是一个域:2没有乘法逆元。(2⋅xmod4=1无解)
模p的除法
我们稍后会定义在Fp上的椭圆曲线,但在这之前我们要搞清楚x/y在Fp上表示什么含义。公式:x/y=x⋅y−1,即x除以y表示x乘以y的乘法逆元。x/y的解法是:找到y的逆元,再做一次乘法。
计算乘法逆元可以用扩展欧几里得算法来计算,最坏的情况时间复杂度是O(logp)(或者O(k),如果考虑位长)。
在这里不讨论扩展欧几里得算法的细节,下面是Python的实现:
def extended_euclidean_algorithm(a, b):
"""
Returns a three-tuple (gcd, x, y) such that
a * x + b * y == gcd, where gcd is the greatest
common divisor of a and b.
This function implements the extended Euclidean
algorithm and runs in O(log b) in the worst case.
"""
s, old_s = 0, 1
t, old_t = 1, 0
r, old_r = b, a
while r != 0:
quotient = old_r // r
old_r, r = r, old_r - quotient * r
old_s, s = s, old_s - quotient * s
old_t, t = t, old_t - quotient * t
return old_r, old_s, old_t
def inverse_of(n, p):
"""
Returns the multiplicative inverse of
n modulo p.
This function returns an integer m such that
(n * m) % p == 1.
"""
gcd, x, y = extended_euclidean_algorithm(n, p)
assert (n * x + p * y) % p == gcd
if gcd != 1:
# Either n is 0, or p is not a prime number.
raise ValueError(
'{} has no multiplicative inverse '
'modulo {}'.format(n, p))
else:
return x % p
在Fp上的椭圆曲线
我们已经具备了Fp上定义椭圆曲线的条件. 在上一篇椭圆曲线的点集:
{(x,y)∈R2|y2=x3+ax+b,4a3+27b2≠0} ∪ {0}改为:
{(x,y)∈(Fp)2|y2≡x3+ax+b(modp),4a3+27b2≢0(modp)} ∪ {0}0仍然是无限远点,a和b是Fp上任意整数。


之前的图像是一个连续的曲线,而现在是不连贯的点。但我们仍然可以证明Fp上的椭圆曲线满足阿贝尔群。
点相加
很显然,我们要稍微修改一下加法的定义,使它可以在Fp上工作。在实数域上,我们定义三个共线的点之和等于0(P+Q+R=0)。我们保留这个定义,那么在Fp上三点共线意味者什么?
我们可以说三点共线表示三个点在一条直线上,但是在Fp上的直线和R上的直线不一样。简单的说,Fp上的直线上的点集(x,y)满足ax+by+c≡0(modp)(这是标准直线公式,再加上”(mod p)”)

在群中,我们保留了加法的属性:
- Q+0=0+Q=Q(集合元素的定义)
- 给定非0点Q,它的逆元−Q是横坐标相同而纵坐标相反的点,也可以表示为−Q=(xQ,−yQmodp)。例如,如果曲线在F29上有点Q=(2,5),它的逆元是−Q=(2,−5mod29)=(2,24)。
- 当然,P+(−P)=0(逆元定义)
代数和
计算点之和与上一篇一样,只是要注意在每一个算式后面添加“mod p”。因此,假设P=(xP,yP),Q=(xQ,yQ),R=(xR,yR),我们可以计算P+Q=−R:
xR=(m2−xP−xQ)modpyR=[yP+m(xR−xP)]modp=[yQ+m(xR−xQ)]modp如果P≠Q,斜率m: m=(yP−yQ)(xP−xQ)−1modp 如果P=Q: m=(3x2P+a)(2yP)−1modp
等式没有发生改变。实际上,这些等式在任何域中都成立,有限域或无限域(F2和F3除外)。困难是这个证明需要很复杂的数学概念,幸好我找到了只使用基本概念的证明方法Stefan Friedl证明。如果您对“为什么这个公式在每个域都成立”感兴趣,可以读一读。
我们没有定义它的几何方法,因为这存在一些困难。比如在上一篇我们计算P+P时需要画P点的切线。但是对于非连续的点,“切线”是没有意义的。我们可以解决这个问题,但是纯粹的几何方法在这里是非常复杂、没有意义的。
您可以使用可视化工具来直观感受点的加法。
椭圆曲线群的阶
我们说在有限域上椭圆曲线包含有限个点。那么有一个重要的问题:到底有多少个点?
首先,让我们称群上点的数量为群的阶
尝试从0到p−1所有的x对应的点是不可行的,当p很大时,需要O(p)次计算是很“困难”的。
幸好,Schoof算法可以很快算出来,这里就不延伸到算法的细节了。
数乘和循环子群
在实数域上,数乘定义为: nP=P+P+⋯+P⏟n times 同样的,我们可以用倍数相加算法去计算(时间复杂度为O(logn)或者O(k),k表示n的位数))。这是数乘的可视化工具。
在Fp上的椭圆曲线点的数乘有一个有趣的特性。假设有曲线y2≡x3+2x+3(mod97)和其上的点P=(3,6),计算P的数乘:

- 0P=0
- 1P=(3,6)
- 2P=(80,10)
- 3P=(80,87)
- 4P=(3,91)
- 5P=0
- 6P=(3,6)
- 7P=(80,10)
- 8P=(80,87)
- 9P=(3,91)
- …
可以发现两个结论:P的数乘只有五个结果,其他的点都没有出现;结果是循环重复的。我们可以写成:
- 5kP=0
- (5k+1)P=P
- (5k+2)P=2P
- (5k+3)P=3P
- (5k+4)P=4P
五个等式可以合成为一个kP=(kmod5)P。
同时,我们可以证明这五个点在加法下是封闭的。也就是说,当这五个点中的任意数量点相加,结果还是在五个点上。曲线上的其他点不会出现在结果中。
这个结论对任意的点都成立,假设有点P: nP+mP=P+⋯+P⏟n times+P+⋯+P⏟m times=(n+m)P
这意味着:如果两个P的数乘相加,可以得到一个P的数乘(P的数乘在加法下是封闭的)。这就可以证明P的数乘结果是椭圆群的一个子群。
“子群”是另一个群的子集。“循环子群”表示元素是循环的,就像上面的例子。点P被称作循环子群的基点。
循环子群是ECC和其他加密系统的基础。在下一篇文章中我们会解释其原因。
子群的阶
我们提出一个问题:由基点P生成的子群的阶是多少(或者说基点P的阶是多少)?这个问题不能通过Schoof算法来计算,因为Schoof算法只能作用于整个曲线。我们需要一些准备工作:
- 到现在为止,我们定义阶为群中点的个数。这个定义依旧有效,但是在循环子群中,我们给出一个等价定义:P的阶表示为一个最小的正整数n,使得nP=0。在上面的例子中,子群包含5个点,得出5P=0。
- P的阶和曲线的阶可以通过拉格朗日定理联系起来:子群的阶能被其父群的阶整除,换句话说,如果椭圆曲线包含N个点,它的一个子群包含n个点,那么n能被N整除。
结合上面的两点,我们可以得出以P为基点的子群的阶的计算方法:
- 用Schoof算法计算椭圆曲线的阶N。
- 找到N所有的约数。
- 对于约数集合中任意的n,计算nP。
- 找到最小的n,使得nP=0,则n就是子群的阶。
举例:在有限域F37上的曲线y2=x3−x+3的阶N=42。它的子群可能的阶为n=1,2,3,6,7,14,21或42。如果尝试P=(2,3),我们可以发现P≠0,2P≠0,…,7P=0,因此P的阶是n=7。
值得注意的是,阶一定选取最小的满足条件的值,而不是随机的。如果我们随机取值,上面的例子可能取n=14,这不是P的阶。
再举例:在有限域F29上的曲线y2=x3−x+1的阶N=37,是一个素数。它的子群的阶只能是n=1或37。当n=1时,子群只包含一个无限远点;当n=N时,子群包含曲线的所有点。
计算基点
在实际的ECC算法中,我们需要子群拥有很高的阶。通常我们先选择一个椭圆曲线,计算它的阶。然后选择一个比较大的约数作为子群的阶。最后找到对应的基点。这就意味着,并不是先拥有了基点再计算子群的阶,而是反过来:我们先确定一个阶,再计算对应的基点。那么怎么做呢?
首先,介绍一下更多的属于。根据拉格朗日定理h=N/n总是一个整数。称h为子群的辅因子。
对于曲线上的任意一点P都有NP=0,因为N是任意n的倍数。使用辅因子: n(hP)=0
假设n是一个素数(在下一篇解释原因),这个等式表示点G=hP生成了阶n的子群(除非G=hP=0,那么子群的阶为1)
由此,算法概述如下;
- 计算椭圆曲线的阶N。
- 选择子群的阶n,这个值必须是素数而且能被N整除。
- 计算辅因子h=N/n。
- 随机选择曲线上的任意一点P。
- 计算G=hP。
- 如果G等于0,从第4步开始重复。否则,就找到了一个阶为n且辅因子为h的子群。
注意:n必须是素数,否则G的阶有可能是n的一个约数。
离散对数
和我实数域上连续的椭圆曲线一样,我们也需要讨论一个问题:如果我们知道了点P和点Q,能否找到值k,使得Q=kP?
这个问题成为椭圆曲线上的离散对数问题,是公认的“困难”问题。虽然不能从数学上证明,但至今没有一种在经典计算机上的多项式时间解决办法。(译者注:这个问题不抗量子计算)
这个问题和其他密码学的离散对数问题一样,比如数字签名算法(DSA)、Diffie-Hellman交换key算法(DH)以及ElGamal加密算法。区别是,其他算法使用模幂来代替数乘,也就是说:如果我们知道了a和b,如何找到k使得b=akmodP?
这些算法被称为“离散”的,是因为它们涉及有限集合(更准确的说,是循环子群)。而“对数”是因为它们类似普通的对数形式。
对于ECC而言,它的离散对数问题比其他加密算法更“难”。这意味着可以使用更少的比特来达到与其他加密算法相同的安全级别,关于这部分将在最后一篇详解。
下周内容
希望大家喜欢这篇文章。
下周将涉及ECC的算法:密钥对的生成,ECDH和ECDSA。这是本系列中最有趣的部分,不要错过!