Skip to content

EC基本方案

ECDH(密钥交换)

密钥生成

私钥生成

私钥 d 是一个随机整数,满足:

1dn1

公钥生成

公钥 Q 通过标量乘法计算:

Q=dG

密钥交换

Alice 和 Bob 通过以下步骤交换密钥:

  1. Alice 生成私钥 dA 和公钥 QA=dAG,将 QA 发送给 Bob。
  2. Bob 生成私钥 dB 和公钥 QB=dBG,将 QB 发送给 Alice。
  3. Alice 接收到 QB 后,计算共享密钥:KA=dAQB=dA(dBG)=(dAdB)G
  4. Bob 接收到 QA 后,计算共享密钥:KB=dBQA=dB(dAG)=(dBdA)G
  5. 最终得到相同共享密钥 K=(dAdB)G

ECIES(公钥加密)

密钥生成

私钥生成

私钥 d 是一个随机整数,满足:

1dn1

公钥生成

公钥 Q 通过标量乘法计算:

Q=dG

加密过程

给定消息 M 和公钥 Q,ECIES加密过程如下:

  1. 生成随机数 k,满足 1kn1
  2. 计算点 P=kG=(x1,y1)
  3. 计算公钥 K=kQ=kdG
  4. 生成对称密钥 Ksym=H(K),其中 H 是哈希函数。
  5. 加密消息 C=MKsym
  6. 输出密文 (C,P)
  7. 发送密文 (C,P) 给接收方。

解密过程

给定密文 (C,P) 和私钥 d,ECIES解密过程如下:

  1. 计算共享密钥 K=dP=dkG
  2. 生成对称密钥 Ksym=H(K)
  3. 解密消息 M=CKsym
  4. 输出明文 M

ECDSA(签名)

域参数

  • p:有限域的大小
  • a,b:椭圆曲线参数
  • G:基点(生成元)
  • n:基点的阶(即 nG=O

密钥生成

私钥生成

私钥 d 是一个随机整数,满足:

1dn1

公钥生成

公钥 Q 通过标量乘法计算:

Q=dG

其中 G 是椭圆曲线的基点。

签名生成

给定消息的哈希值 h 和私钥 d,ECDSA签名过程如下:

步骤1:生成随机数

生成一个随机数 k,满足:

1kn1

!!!:这里是简化的,具体参照这里,简单说就是Hash(h||d)

步骤2:计算点

计算椭圆曲线点:

P=kG=(x1,y1)

步骤3:计算 r

r=x1modn

!!!:取点 Px 坐标模 n,作为签名的第一部分。如果 r=0,则重新选择 k

步骤4:计算 s

s=k1(h+rd)modn

!!!

  • k1k 在模 n 下的乘法逆元
  • (h+rd) 将消息哈希与私钥信息结合
  • 整个表达式确保了签名与私钥和消息的绑定关系

如果 s=0,则重新选择 k

步骤5:输出签名

签名为 (r,s)

签名验证

给定消息哈希 h、签名 (r,s) 和公钥 Q,验证过程如下:

步骤1:参数验证

验证 rs 在有效范围内:

1rn11sn1

步骤2:计算逆元

计算 s 的乘法逆元:

w=s1modn

步骤3:计算标量

u1=hwmodnu2=rwmodn

步骤4:计算验证点

P=u1G+u2Q=(x1,y1)

步骤5:验证结果

如果 x1modn=r,则签名有效;否则无效。

数学原理

从签名生成有:

s=k1(h+rd)modn

重排得到:

k=s1(h+rd)modn(α)

在验证过程中:

P=u1G+u2Q

替换 u1u2

P=(hs1)G+(rs1)Q

由于 Q=dG

P=(hs1)G+(rs1)(dG)P=s1(h+rd)G

根据签名生成中(式α)的关系:

P=kG=P

这证明了验证点 Px 坐标确实等于 r,从而验证了签名的有效性。

Add-On: v的生成与公钥恢复

由于压缩传输空间的需要以及ECDSA可以从签名恢复公钥的性质,往往只传输 (r,s) ,而不传输公钥 Q

在以太坊中,需要一个 v(也叫 recovery id,记作 recId)与 (r,s) 一起传输,使得验证者可以从签名中恢复出公钥 Q(进而得到地址)。

1) v/recId 到底在表达什么

ECDSA 签名里有中间点:

R=kG=(xR,yR)

而签名的

rxR(modn)

因此仅凭 r 并不能唯一确定 R

  • 同一个 x 往往对应两个点(yy),需要 1 bit 表示 y 的奇偶性(或“是否取较大/较小根”)。
  • 由于 xR 是在有限域 Fp 上的坐标,而 r 是模 n 的结果,可能存在xR=r+jn(j{0,1})需要再用 1 bit 表示 j

所以常见的恢复标识是:

recId{0,1,2,3}

其中通常可理解为:

  • recIdmod2:选择 y 的奇偶性(对应两种 R
  • recId/2:表示是否使用 x=r+n(即 j

2) 以太坊里的 v

历史上(黄皮书/早期实现)以太坊把 recId 平移为:

v{27,28},v=recId+27(recId{0,1})

引入 EIP-155(防重放)后,交易签名里常见:

v=recId+35+2chainId

因此从交易的 v 还原 recId 通常是:

  • v{27,28}recId=v27
  • 否则(EIP-155):recId=v(35+2chainId)

备注:不同库/链的编码细节可能略有差异,但核心都是携带“恢复所需的那几 bit”。


3) 从 (r,s,v) 恢复公钥 Q

ECDSA 有:

sk1(h+rd)(modn)

两边乘以 k

skh+rd(modn)

又因为 R=kG,于是:

sR=s(kG)=(sk)G(h+rd)G=hG+r(dG)=hG+rQ

移项得到:

rQsRhG(modn)

从而:

Qr1(sRhG)(modn)

这就是“公钥恢复”的核心:只要能确定 R,就能算出 Q
v/recId 的作用,就是帮助从 r 选出正确的 R


4) 具体步骤

给定曲线参数 (p,a,b,G,n)、消息哈希 h、签名 (r,s)recId

  1. 范围检查1r,sn1
  2. r 构造候选 x
    j=recId/2{0,1},取x=r+jnxp 则该候选无效(这一分支失败)。
  3. 在曲线上解出点 R
    计算y2x3+ax+b(modp)若无解则该候选无效;若有两解 ±y,用 recIdmod2 决定取哪个(例如选与奇偶性匹配的那个),得到R=(x,y)
  4. 计算公钥Q=r1(sRhG)得到候选公钥 Q
  5. 校验
    用恢复出来的 Q(r,s) 做一次标准 ECDSA 验签;通过则恢复成功,否则尝试其他候选(在实现里就是不同的 recId 分支)。