2021SC@SDUSC

ECDSA和ECDH原理

  • secp256k1的参数
  • ECDSA椭圆曲线数字签名算法
    • 公钥生成
    • 签名
    • 签名验证
    • k
    • 公钥恢复
  • ECDH椭圆曲线Diffie–Hellman秘钥交换

本文我会讲解如何使用椭圆曲线secp256k1通过私钥生成公钥、进行数字签名和签名验证,同时说明在签名过程中要注意的随机数k。

secp256k1的参数

前面提到,我们要合理选取椭圆曲线的两个参数a和b的取值,生成元P点的选取,以及选一个足够大的素数p,让椭圆曲线这个群足够大,并让生成元P经过多次几何加法运算生成的循环子群足够大,大到可以遍历椭圆曲线群内全部的点。在secp256k1的标准定义中,生成元是G,所以在下文中我们改用G描述。

在secp256k1中,定义a=0,b=7,也就是说在secp256k1中椭圆曲线方程就是y2=x3+7y^2 = x^3 + 7y2=x3+7 ,当然在有限域中我们应该写作y2=(x3+7)modpy^2 =( x^3 + 7 )\,mod\,py2=(x3+7)modp。
有了这两个参数,我们就可以在实数域中唯一确定椭圆曲线的长相了,大概就是下图这样:

但是想在有限域中看到这个图像的样子却有些困难,因为在有限域中除了需要知道a和b的值外我们还需要一个素数p,为了让有限域足够大,素数又选的很大,在secp256k1中,素数p值为:

这个数大概是10的77次方数量级的,可以想象在一个长宽均为这么大的正方形里面有密密麻麻的满足y^2 =( x^3 + 7 ) mod p 的点,这些点关于 y=p/2 对称。这么说或许脑海中已经有个雏形了,那么我们还比较感兴趣的是这个图像里面到底有多少个点(包含一个无穷远点),也就是这个椭圆曲线的秩是多少。答案是:

又是一个天文数字,但我们的担心又来了:如果我在上面选择一个生成元,经过标量乘法运算,构成的循环子群很小该怎么办,因为上文中我举出过一个例子,群的秩大不代表群上一个点生成的循环子群就大。但我们找到了一个生成元G,它的坐标是:

对这样的一个点,我们不停地用它自己加它自己,也就是G+G+……+G直到最后加完的结果得到G的坐标,也就是又回到了G本身,形成一个循环群,或者我们可以表述为满足nG=G的n是多大,答案是这个n和椭圆曲线的秩一样大。也就是说这一整个椭圆曲线群就是一个循环群,它的生成元就是G,这个循环群里面一共有n个点。可以看出来这个a和b的取值,生成元G点的选取,以及足够大的素数p的选取都是非常巧妙的。

上文中椭圆曲线参数数据来自: https://en.bitcoin.it/wiki/Secp256k1.

ECDSA椭圆曲线数字签名算法

公钥生成

首先在说签名之前先来说如何根据私钥生成公钥。其中私钥就是{1,2,3……,n-1}中的随机的一个值,这个n就是上文椭圆曲线的秩n,可见私钥可以选择的空间还是非常大的。那么公钥就是通过私钥生成的,生成的方法就是标量乘法,用nG得到的椭圆曲线上的一个点就是公钥。由于这个循环群遍布群的所有点,因此私钥和公钥其实就是一一对应的,唯一的私钥确定公钥,公钥又同时对应一个私钥。
同时我们可以看到,根据私钥生成公钥比较简单,只需要计算出标量乘法的结果就行了,换句话说,对G点做“私钥”次几何加法得到的就是公钥了,但我们没必要真一个个加,可以G+G得2G,然后2G+2G得4G……用指数方式滚雪球算,这样的话做的次数最多就是 log22256log_22^{256}log2​2256 ,也就是几百次的几何加法,这对计算机来说还是非常容易完成的;但是根据公钥找到私钥确是非常困难的(这个求解困难性问题称之为椭圆曲线上的离散对数问题ECDLP),因为{1,2,3……,n-1}中任何一个数都可能是私钥,我们只有几何加法和标量乘法,也没人告诉我们反过来怎么做,更没法用滚雪球指数的方法算,因为滚一个雪球可能就少试了一大堆私钥的可能取值。唯一可行的办法就是穷举攻击:把n代入一个个试,直到结果恰好等于公钥为止。或许试n个数也没那么难,但这个n这么大:
私钥求公钥,我们进行几百次几何加法运算就可以,但根据公钥求私钥要进行n次几何加法运算,这个次数是 22562^{256}2256 数量级的,可想而知这其中的难度跨度有多大。
对于这种数或许都不会特别敏感,只有告诉我们计算机破解这个结果到底要花多少年我们才有个更加直观的的感受。下图是《密码编码学与网络安全》中的一组数据:

可以看到128位的密钥都要540000000年,更何况secp256k1中n的二进制表示是256位,破解所花的年数必然是个天文数字。因此这个私钥生成公钥还是挺安全的。

最后我们给私钥和公钥给出符号表示:
HA=dAGH_A=d_AGHA​=dA​G

其中dAd_AdA​就是私钥,HAH_AHA​就是公钥,其中:
私钥就是一个整数,用二进制表示的话有256位;
G就是那个有固定xy坐标的椭圆曲线循环群生成元;
HAH_AHA​就是有限域椭圆曲线中的某一个点,它具有横纵坐标。

签名

签名就是使用私钥对要签名的文件进行签名。所以这里要签名的一方需要准备两个量:发送方本人的私钥和要签名的文件。签名要经过六步,下面开始:

第一步,在{1,2,3……,n-1}中取一个随机数k。这里的n就是椭圆曲线的秩,也就是椭圆曲线中点的个数,因此随机数k就是一个二进制256位的数字。

第二步,计算P=kGP=kGP=kG其中G是子群的生成元。这里得到的P点实际上就是椭圆曲线上的某一个点,它具有横纵坐标。

第三步,计算r=xPmodnr=x_P\, mod \, nr=xP​modn

其中xPx_PxP​是P点的横坐标,P点的横坐标最大为素数p(当然也可能取不到最大),也就是椭圆曲线横纵坐标能达到的最大值,前面提到p的值为

而n为

因此P点的横坐标xP很有可能会比n大,因此需要进行一个取模运算得到一个不大于n的二进制256位数r。

第四步,计算z=Hash(message)z=Hash(message)z=Hash(message)

Hash就是一个函数,它可以将任意长度的比特串生成一个定长的比特串,并且将比特串即便只改变一位得到的哈希结果也会天差地别(雪崩效应),并且哈希具有不可逆性,即我可以将一个比特串哈希,但很难给定一个哈希结果说出来那个哈希前的比特串(除非这个对应关系你记录过,用数学的方法难以求解)。区块链比特币中常使用哈希函数有SHA-256,一个任意长度的比特串被SHA-256哈希后的结果就是是256位的定长比特串。

第五步,计算s=k−1(z+rdA)modns=k^{-1}(z+rd_A) \,mod \,ns=k−1(z+rdA​)modn

其中k−1k^{-1}k−1就是模n下k的乘法逆元(满足该乘法逆元与k的乘积对n取模结果为一,用扩展欧几里得算法来求),z和r就是第四、三步分别介绍的,dAd_AdA​就是私钥。经过有限域GF(n)GF(n)GF(n)加法模运算和乘法模运算运算结果就是s。
第六步,生成数字签名(r,s)。数字签名就是r和s摆在一起组合成的512位(r和s各256位)比特串(这个过程在编译原理中称之为连接)。这样就得到了数字签名。

签名验证

签名验证就是验证签名是否正确,防止有人伪造签名,如果签名验证通过,那么至少可以证明发出这个文件的确实就是正确的发送方而不是什么别的人。

在说验签之前先需要梳理一下目前接收方的已知量,因为签名是发送方本人签名,而验签是所有人都可以验证,所以有些东西是只有发送方知道的,有些东西可以让任何人都知道。目前我们有签名生成过程中的一些中间量如r、s、z,其中r和s构成了数字签名,z是接收方对接收到的数据取哈希结果,在区块链比特币中通常称z为哈希数字摘要,这三个量对接收方都是已知的。此外还要椭圆曲线的两个参数a和b,大素数p,循环群生成元G,椭圆曲线群的秩n,secp256k1是个公开的算法,我都可以在网上找到这些参数,那这些参数也就是公开的,接收方肯定也会知道。此外还有公钥HAH_AHA​也是公开的,在“公钥生成”部分我也说过根据公钥要花几亿年才能求出私钥。此外还有一个随机数k,下一个目录会讲。

验签的过程一共有四步:
第一步,使用如下公式求出u1u_1u1​和u2u_2u2​,其中s−1s^{-1}s−1就是s对模n的乘法逆元,z和r都是接收方已知量,因此我们容易得到u1u_1u1​和u2u_2u2​。
u1=s−1zmodnu2=s−1rmodnu_1=s^{-1}z\,mod\,n\\u_2=s^{-1}r\,mod\,nu1​=s−1zmodnu2​=s−1rmodn

第二步,计算Q。由于GGG和HAH_AHA​都是椭圆曲线上的点u1u_1u1​和u2u_2u2​都是256位比特串,因此这就相当于对GGG和HAH_AHA​进行了标量乘法运算,在“公钥生成”部分提到最多不超过200多步就可以算出标量乘法的结果。计算出新的两个点u1Gu_1Gu1​G和u2HAu_2H_Au2​HA​进行几何加法运算,在上一篇博客中详细阐述了计算的方法,得到的结果是Q。
Q=u1G+u2HAQ=u_1G+u_2H_AQ=u1​G+u2​HA​
第三步,计算rQr_QrQ​。由于Q是一个点,它必然有横坐标值xQx_QxQ​,对n取模后得到一个256位比特串rQr_QrQ​。
rQ=xQmodnr_Q=x_Q\,mod\,nrQ​=xQ​modn

第四步,验证rQ是否与r相等,如果相等,则签名正确。
rQ=r是否成立r_Q=r\,是否成立rQ​=r是否成立
在这整个过程中我们可以看到,我们没有用到任何接收方不该知道的量就验证了签名的正确性,而且计算过程并不复杂,也不需要大的算量,计算机可以很容易地完成。

k

最后你可能会发现一个问题,签名过程中用到了一个随机数k,在验证签名的时候我没有用到它。那么这个k是不是可以随意公开或者消息签名时多次使用呢?答案是k既不能泄露,也不能相同。历史上也有许多使用相同k导致泄密的前车之鉴。

首先先说为什么k不能泄露。
首先我们有这样一个式子:
s=k−1(z+rdA)modns=k^{-1}(z+rd_A)\,mod\,ns=k−1(z+rdA​)modn
在这个式子里面,r和s在签名中是公开的,z是文件哈希值也是公开的。如果我们移移项,就会有个很大的发现:
dA=r−1(sk−z)modnd_A=r^{-1}(sk-z)\,mod\,ndA​=r−1(sk−z)modn

这个式子就等于告诉别人,如果k泄露,私钥dAd_AdA​就可以很容易地求出来,私钥就泄露了,私钥泄露你发送的信息就都泄露了。

然后再来说说为什么k不能重复使用。
首先一般人肯定有个疑惑,一个人甚至一个公司要发送那么多文件,我怎么知道他是不是用了重复的k,如果他只有几份文件用了相同的k我也很难辨别找出来。这个问题我下面会回答。
首先假设两个签名用了一样的k,但这两个签名签在了不同的文件上,可以令两个签名分别为(r1,s1)和(r2,s2),签名的文件哈希分别为z1和z2。a,b,p,G,n都是公开的,哪个文件签名都用。公钥HA由私钥生成,一个人发的文件私钥一样公钥肯定也一样。
对签名过程生成r的时候是这么生成的:
P=kGr=xPmodnP=kG\\r=x_P\,mod\,nP=kGr=xP​modn
在这个过程中很容易可以看出来,G固定如果k一样,那么P一定一样,P一样那么它的横坐标xPx_PxP​肯定定值,n固定那么r肯定也一样,那么前面的r1和r2肯定会一样。这样就可以回答之前的问题了,判断是不是用了重复的k很简单,只要看签名的前256位(也就是r部分)是不是完全一样就行了,如果完全一样那必然就是用了一样的k。
接下来首先对这个数字签名s部分生成的式子:
s=k−1(z+rdA)modns=k^{-1}(z+rd_A)\,mod\,ns=k−1(z+rdA​)modn
如果是同一个人发送的数据必然使用相同的私钥dA,如果使用相同的k那么r1=r2,那么rdAr d_ArdA​这一项就相同。如果代入s1 z1 s2 z2不难构造下面的式子:
(s1−s2)modn=k−1(z1−z2)modnk(s1−s2)modn=(z1−z2)modnk=(z1−z2)(s1−s2)−1modn(s_1-s_2)\,mod\,n=k^{-1}(z_1-z_2)\,mod\,n\\k(s_1-s_2)\,mod\,n=(z_1-z_2)\,mod\,n\\k=(z_1-z_2)(s_1-s_2)^{-1}\,mod\,n(s1​−s2​)modn=k−1(z1​−z2​)modnk(s1​−s2​)modn=(z1​−z2​)modnk=(z1​−z2​)(s1​−s2​)−1modn

通过这三个式子可以看到,如果两份文件r的一样我们推出来k一样,那么我们完全可以使用两个文件的z1 z2 s1 s2来计算得到k,计算得到k就又回到k泄露问题了,上面也提到泄露了k就是泄露了私钥,因此k也绝对不能重复使用。

不过好在上面我们推导关键步骤还是基于相同私钥,也就说两个人碰巧用了相同的k(不过这概率还是很低,毕竟k取值是{1,2,3……,n-1}中的一个,而n又无比巨大),由于使用不同的私钥因而还是无法攻破他们各自的私钥,因此只要是一个私钥就别用相同的k就行了。

公钥恢复

签名者的公钥可以在数字签名中进行恢复,下面说恢复的原理:

首先在签名过程中有如下三个式子:u1=s−1zmodnu2=s−1rmodnQ=u1G+u2HAu_1=s^{-1}z\,mod\,n\\u_2=s^{-1}r\,mod\,n\\Q=u_1G+u_2H_Au1​=s−1zmodnu2​=s−1rmodnQ=u1​G+u2​HA​
将这三个式子联立可得:Q=(zG−rHA)s−1Q = (zG - rH_A)s^{-1 } Q=(zG−rHA​)s−1
且进一步推得:Q=(zG−rHA)s−1⇒HA=(sQ−zG)r−1Q = (zG - rH_A)s^{-1 } \Rightarrow H_A = (sQ - zG)r^{-1}Q=(zG−rHA​)s−1⇒HA​=(sQ−zG)r−1
在签名验证时有一步要验证rrr与rQr_QrQ​是否相等,这里如果数字签名就是私钥和公钥的所属方,那么rrr与rQr_QrQ​必然相等,由rQ=xQmodnr_Q=x_Q\,mod\,nrQ​=xQ​modn,则rrr实际上就是Q点的横坐标。在数字签名的前半部分得到rrr,将其作为横坐标放入椭圆曲线方程中就可以得到Q点的纵坐标,有了Q点的横纵坐标就可以得到公钥HAH_AHA​,就在数字签名中恢复出了签名者的公钥。

也就是说公钥恢复的实际步骤为:

先将数字签名的rrr部分代入到椭圆曲线方程中得到一个纵坐标,将rrr作为横坐标,在方程中得到的纵坐标,组合成一个点QQQ。

计算HA=(sQ−zG)r−1H_A = (sQ - zG)r^{-1}HA​=(sQ−zG)r−1得到公钥。

ECDH椭圆曲线Diffie–Hellman秘钥交换

ECDH是一种加密方法,用于生成通信双方的共享密钥。

首先通信双方A和B分别在本地生成私钥,然后私钥生成公钥:HA=dAGHB=dBGH_A=d_AG\\H_B=d_BGHA​=dA​GHB​=dB​G这时候双方都就有了自己的私钥和公钥,接下来生成共享私钥,A用自己的私钥与B的公钥进行标量乘法运算,同时B用自己的私钥与A的公钥进行标量乘法运算,即S=dAHBS=dBHAS=d_AH_B\\S=d_BH_AS=dA​HB​S=dB​HA​可以发现S其实是相同的:S=dAdBGS=d_Ad_BGS=dA​dB​G然后A和B就可以用这个共享密钥用对称加密的方式对消息加解密了。

ECDSA和ECDH原理相关推荐

  1. 【密码算法 之零】对称算法(DES,、3DES、 AES、DM5、HMAC、CMAC、SHAxx、SM3、SM4),非对称算法(RSA、ECC、ECDSA、ECDH、SM2、SM9...)

      由于工作的需要,在过去的两年中学习.适配了很多算法,包括对称算法.非对称算法.国密算法.国际算法等.为了逼迫自己能够牢记并掌握这些算法的基本知识点,故本人写了一个关于算法的专栏(持续更新中...) ...

  2. DH密钥交换和ECDH原理

    DH密钥交换和ECDH原理 上述的就是DH密钥交互的图表: 可以这么理解,A与B想要生成只有彼此知道的密钥,而使得自己本地产生的私钥,不被对方知道,包括第三方的Eve. 此时的Alice 和Bob 彼 ...

  3. java ecdh算法_椭圆曲线ECC ECDH原理 javacard实现

    椭圆曲线原理: 椭圆曲线的图像并不是椭圆形,椭圆曲线源自于求椭圆弧长的椭圆积分的反函数. 定义: 椭圆曲线可用下列方程来表示,其中a,b,c,d为系数. E: y2 =ax3 + bx2 +cx +d ...

  4. java ecdh秘钥交换_DH密钥交换和ECDH原理(转)

    下面我们以Alice和Bob为例叙述Diffie-Hellman密钥交换的原理. 1,Diffie-Hellman交换过程中涉及到的所有参与者定义一个组,在这个组中定义一个大质数p,底数g. 2,Di ...

  5. 【密码算法 之十四】非对称算法,ECC椭圆曲线算法 之 ECDSA、ECDH、SM2、SM9等

    文章目录 1. ECC椭圆曲线 1.1 曲线类型 1.2 曲线标准 1.3 表示方法 1.4 曲线运算 1.4.1 点加(Point Addition) 1.4.2 点乘(Point Multipli ...

  6. java调用ecdh_椭圆曲线ECC ECDH原理 javacard实现

    椭圆曲线原理: 椭圆曲线的图像并不是椭圆形,椭圆曲线源自于求椭圆弧长的椭圆积分的反函数. 定义: 椭圆曲线可用下列方程来表示,其中a,b,c,d为系数. E: y2 =ax3 + bx2 +cx +d ...

  7. ECDSA 和 ECDH

    ECDH:       ECC算法用途比RSA还猛,不仅可以加解密.签名验证.还可以与DH结合使用,用于密钥磋商,这个密钥交换算法称为ECDH.交换双方可以在不共享任何秘密的情况下协商出一个密钥.EC ...

  8. MPC Multiparty Threshold ECDSA (GG18实现原理)

    目录 1. 简介 2. Generic DSA signature 2.1. ECDSA 门限签名的难点 3. 主要思路 3.1. 求签名中的 r 3.2. 求签名中的 s 4. 协议描述 4.1.  ...

  9. ECDSA 签名验证原理及C语言实现

    这两天总算把ECDSA搞明白了,本来想造个ECDSA轮子,但最近有点忙,而ECDSA轮子又不像HASH那样简单,所以就直接拿现成的轮子来记录一些ECDSA学习心得. 这里贴上github上一个比较适合 ...

最新文章

  1. python将局部变量转为全局变量
  2. 整图下沉,MindSpore图引擎详解
  3. CSS布局代码:两列布局实例
  4. C语言关于signal()函数
  5. ESXI主机定时重启脚本
  6. Java 9,Jigsaw,JPMS和模块:个人探索
  7. Office 2010 体验系列之Outlook使用
  8. tensorflow之get_shape
  9. 2018 计蒜之道 初赛 第一场
  10. uniapp弹出框_uni-app 弹出框插件 模态框 小程序dialog
  11. 计算机三级考点3:构建宽带城域网的基本技术与方案。
  12. 褚霸:阿里云数据库要放大招!
  13. raize控件的安装注意
  14. VBA-批量删除文本框内容(用类实现)
  15. (2011-12-11 旧博文搬运)闪耀十字军(ティンクル☆くるせいだーす)【1】
  16. 学计算机的女生选择公务员还是考研,女生本科毕业!考研好,还是考公务员更好?...
  17. PDF内容复制自动替换换行符
  18. 1条命令解决使用kubeadm安装 kubernetes 从 k8s.gcr.io 拉取镜像失败的问题
  19. codeforces 892A. Greed(水)
  20. 空洞骑士复活歌女玛丽莎的方法(复活其他灵魂NPC同理)

热门文章

  1. ajax访问带token abp,ABP官方文档(三十八)【AJAX API】
  2. Extjs多选框传值
  3. 庆余年“真的”被大家喜欢吗?Java爬虫分析告诉你结果
  4. 改变页面鼠标样式(为一个可爱的小图标)
  5. 培智学校计算机教材,培智学校信息技术课《美丽的图片》
  6. JavaScriptHelper
  7. QingScan 支持墨菲安全项目 murphysec
  8. 如何从游戏配音试音中辨别质量?
  9. 软件管家matlab2020a,-30天下载
  10. 大华条码秤开发之-标签模板发送