ecdsa算法

ECC

椭圆曲线密码学算法(Elliptic curve cryptography,缩写为ECC),最初由Koblitz和Miller两人于1985年分别独立提出,是一种基于椭圆曲线数学的公开密钥加密算法,其数学基础是利用椭圆曲线上的有理点构成的Abel加法群上椭圆离散对数的计算困难性

ECC的主要优势是在某些情况下它比其他的方法使用更小的密钥——比如RSA算法——提供相当的或更高等级的安全。

椭圆曲线

椭圆曲线的Weierstrass标准形式:

y2=x3+ax+b

当判别式不为0,那么椭圆曲线就是非奇异的,即处处可导:

4a3+27b20

下图是非奇异的椭圆曲线示例。

椭圆曲线上的阿贝尔群

G是一个集合,在集合中定义一个对两个元素的操作,记为"加",用+表示,集合中两个元素ab,“加”操作表示为a+b,如果a+b满足以下5个特性,G就是一个阿贝尔群。

  • 闭合性(closure): 若a,bG中的元素,那么a+b也是。
  • 结合性(associativity): (a+b)+c=a+(b+c).
  • 存在单位元(identity element 0):有a+0=0+a=a.
  • 每个元素都有一个相反数,对每个元素a都存在b使a+b=0, b就是a的相反数,可以表示为a.
  • 交换律:a+b=b+a.

那么可以得到定义在椭圆曲线上的阿贝尔群。

  • 一个椭圆曲线上的点是G中的元素。
  • 单位元0定义为无穷远处的点。
  • 一个点P的相反数是关于x轴对称的点。
  • “加”定义为:P,Q,R是一条直线跟椭圆曲线相交的3个点,那么有P+Q+R=0,也就是P+Q=R.

当点P加上它的相反数P时,那么与椭圆曲线相交于无穷远点,也就是P+(P)=0

椭圆曲线的参数

上述内容简单说明了椭圆曲线算法的定义,但如果要将其转换为计算机能处理的离散算法,还需要做一些椭圆曲线参数上的限制。
椭圆曲线算法中的参数如下。

  1. 椭圆曲线中的系数a,b.
  2. 有限域的大小是个素数p.
  3. 子群基准点G.
  4. 子群的阶n.
  5. 子群的协因子h.

有限域Fp

之前的椭圆曲线是在实数域上的,并不适合计算机处理,所以我们必须把椭圆曲线变成离散的点。在ECC算法中选取模p同余(p为素数)的点来做“加”法。从而得到离散的有限域Fp.

子群的基准点G和子群的阶n

首先需要定义一个椭圆曲线群的阶N,表示该群中点的总量。
子群的基准点G,其实就是椭圆曲线群中的任意一点,选取之后作为基准点。然后对其进行累加(可以转换为标量乘法)。

nG=G+G++G

在有限域中,这样的加法会形成循环,也就是加到某一步nG=0,这时就得到一个基于基准点G的子群,这个子群中一共有n个点。此时n就是这个子群的阶。

  1. 子群的阶就是子群中的元素个数,等价于nG=0,其n是正整数,且n是其中最小的1个,这个n就是这个子群的阶。
  2. 根据拉格朗日定理,子群的阶,是父群阶的一个因子,比如一个椭圆曲线群有N个元素,它的一个子群有n个元素,n能整除N.

子群的协因子h

在实际使用中需要子群大一点,也就是n的值大一点。但是根据基准点来计算n,一个是范围太大,一个是没有直接公式可以计算子群的阶。所以实际中是先计算椭圆曲线群的阶N,这个可以利用Schoof’s algorithm算法计算,然后选取N的一个较大的素因子n作为子群的阶,令h=Nnh就称做子群的协因子。在椭圆曲线中随机选择点P,那么有。

NP=0

n(hP)=0

因为N总是任何一个n的倍数。此时就可以选取G=hP作为这个子群的基准点了。方便快捷。

常用椭圆曲线参数

椭圆曲线的参数可以有多种配置方式,也就存在多种不同的曲线,例如secp256k1secp256r1Curve25519等,不同曲线的安全性存在一些区别,在SafeCurves中有相关对比描述。

secp256k1

secp256k1是高效密码组标准(SECG)协会开发的一套高效的椭圆曲线签名算法标准。在比特币流行之前,secp256k1并未真正使用过。secp256k1命名由几部分组成。

  • sec来自SECG标准。
  • p表示曲线坐标是素数域。
  • 256表示素数是256位长。
  • k表示它是Koblitz曲线的变体。
  • 1表示它是第一个标准中该类型的曲线。

那为什么比特币要选择secp256k1签名算法而不是其他已流行的算法呢?比特币开发者社区曾讨论过secp256k1是否安全。中本聪没有明确解释,只是说道”有根据的推测”。从社区的讨论中,有推测是其它的曲线,比如secp256r1中的参数是美国国安局精心挑选的,相当于安全性受到权威机构的干涉。总的来说选择secp256k1是安全和性能考量的结果。以太坊沿用了比特币中的数字签名算法。
secp256k1的参数如下。

secp256r1

secp256r1是美国国家安全局建议使用的椭圆曲线,里面的r代表曲线的参数是经过随机选取的。它也被称为NIST P-256

ECDSA算法

生成密钥对(genKey)

  1. 确定子群的阶数n,基点G.
  2. 选择随机数d[1,n)作为私钥,并计算出公钥Q=dG.

这里计算dG很简单,但是根据公钥Q和基点G却很难计算出私钥d.

加密(encrypt)

  1. 准备要加密的数据M,随机数r.
  2. 计算密文:C1=M+rQ,C2=rG

解密(decrypt)

  1. C1dC2=M+rQr(dG)=M+rQrQ=M

签名(sign)

  1. 对消息m使用消息摘要算法,得到z=hash(m).
  2. 生成随机数k[1,n),计算点(x,y)=kG.
  3. r=xmodn,若r=0则重新选择随机数k.
  4. 计算s=k1(z+rd)modn,若s=0则重新选择随机数k.
  5. 上述(r,s)即为ECDSA签名。

验证(verify)

使用公钥Q和消息m,对签名(r,s)进行验证。

  1. 验证r,s[1,n).
  2. 计算z=hash(m).
  3. 计算u1=zs1modnu2=rs1modn.
  4. 计算(x,y)=u1G+u2Qmodn.
  5. 判断r==x,若相等则签名验证成功。

恢复(recover)

已知消息m和签名(r,s),恢复计算出公钥Q

  1. 验证r,s[1,n)
  2. 计算R=(x,y),其中x=r,r+n,r+2n...,代入椭圆曲线方程计算获得R.
  3. 计算z=hash(m).
  4. 计算u1=zr1modnu2=sr1modn.
  5. 计算公钥Q=(x,y)=u1G+u2R

recoveryID

在计算R的步骤可以看到,存在多个x的取值可能性,导致存在多个R的可能,因此计算得到的Q也存在多个可能的结果,需要通过和已知的公钥对比,确定哪一个Q是正确的。如果遍历x的所有可能都未找到正确的Q,说明该消息和签名是不对应的,或者是一个未知的公钥。
为了确定正确的Q,需要遍历x的所有可能取值,跑多轮recover算法,这个时间开销是比较大的。为了提高recover的时间效率,采用空间换时间的思路,在签名中增加一个v值,用于快速确定x,避免遍历查找试探,这个v值就是recoveryId
由于r=xmodn,因此r,r+n,r+2n都可能是合法的原始x值,不同的椭圆曲线存在不同数量这样合法的x值,secp256k1曲线存在两个可能r,r+n
每一个X轴坐标对应两个可能的Y坐标,因此secp256k1曲线具备四种可能的R(r,y)(r,y)(r+n,y)(r+n,y)。但是,对于一个r值存在两个X轴坐标的概率极低,低到几乎可以忽略,以太坊中就忽略了这两种小概率事件。
由于r=xmodnx是模p的结果,r是模n的结果,x值的范围是[0,p)r值的范围是[0,n)。如果r+n也是曲线上的点,则r的值必须小于pn,概率为(pn)/p,大约为3.73×1039,这个概率是非常小的。

参考资料

posted @   HachikoT  阅读(3794)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示