鱼C论坛

 找回密码
 立即注册
查看: 167|回复: 0

[技术交流] 零基础完全理解ECC加密算法(软件方法)

[复制链接]
发表于 2024-8-11 00:37:20 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 mlsily 于 2024-8-11 00:44 编辑

1.算法简介
ECC加密算法是在椭圆曲线形成的加法群上的EIG算法(EIG原本是在乘法群上的),是我国二代身份证使用的加密算法。

2.前置知识
椭圆曲线:在实数域上,满足方程y^2 = x^3 + ax + b 的所有点构成的集合。记为椭圆曲线E(a,b)。系数4a^3 + 27b^2 ≠ 0 的椭圆曲线,被称为有效的椭圆曲线。

无穷远点:平行线相交于无穷远点。
E(a,b)只有一个无穷远点,即平行于Y轴的直线相交的点,记为{O}。
无穷远点是加法运算的单位元。

椭圆曲线上的加法运算:任取E(a,b)上两点P和Q,过P、Q的直线交E(a,b)于点R(当P、Q重合则在该点做E(a,b)的切线),过点R做Y轴的平行线交E(a,b)于R',定义P+Q = R'。
由定义进行推导可得出公式:若P ≠ Q,斜率k = (y1-y2)/(x1-x2),若P=Q,斜率k = (3x1^2 +a)/2y1。 P+Q = (k^2 -x1-x2,k(x1-x3)-y1 )。


3. 算法原理

1.生成椭圆曲线Ep(a,b)。
2.取曲线上一点G。
3.选取整数k,1<k<|Ep(a,b)|(|Ep(a,b)|表示曲线|Ep(a,b)|上的点的数量,即曲线Ep(a,b)构成的加法群的阶。)
4. 计算K = kG  (即k个G相加)
公钥:(Ep(a,b),G,K)
私钥:k
加密过程:将明文m编码为Ep(a,b)上的一点M,生成随机整数r(1<r<|Ep(a,b)|),
                计算C1 = rG, C2 = M+rK
                密文为C1,C2
解密过程:M = C2-rK = C2 - rkG = C2 - krG = C2 - kC1
                对M解码即得到明文。


4.椭圆曲线Ep(a,b)的生成

由于我们要使用的是有限元的加法循环群,所以我们要求定义的椭圆曲线上只有整数点,故使用mod p运算定义曲线。
生成一个大于3的素数p
7定义椭圆曲线Ep(a,b):选取a,b属于mod p 的剩余系,有 (4a^3+27b^2)mod p ≠ 0, 则有Ep(a,b) = {(x,y)|y^2=x^3+ax+b,x,y∈Zp}∪{O}
与上面的实数域的定义方式相同,只是挪到了mod p 的整数域上。这样的曲线被成为素曲线。


5.ECC算法的安全性
与EIG相同,ECC算法同样基于离散对数难题。这要求我们使用足够大的素数p,以保证我们选择的K 构成的群有足够大的阶,以保证离散对数表的复杂度。
所以,在生成椭圆曲线之后,我们需要对曲线的阶进行验证,以保证加密算法的安全性。一般我们使用SEA( Schoof-Elkies-Atkin,不是图像处理的SEA算法)算法对椭圆曲线的阶进行求解。这是一直复杂度很高的算法,需要进行大量的计算。同时我们要求生成的椭圆曲线的阶不能被多个小质数分解,同时随机选择的基点G具有大素数阶,即保证我们算法使用的在该椭圆曲线上的子群应该有足够大的阶,这同样需要对这个子群的阶进行计算。
由于曲线的生成需要大量的验证运算,所以我们平时使用时并不自己生成椭圆曲线,而是选择一条已经经过验证的曲线使用。


6.明文嵌入
在对明文使用ECC加密前,需要将明文m编码为曲线Ep(a,b)上的一个点M。
1.计算点Q = rK = (qx,qy)
2.设将发送的两个明文分组分别为m1,m2。
c1 = rG
c2 = M+rK = (m1,m2)+(qx,qy) =  (m1*qx) mod p,(m2*qy)mod p (即点的加法转换为向量的乘法,实际上加密后的点并不在椭圆曲线上,但解密后依然具有等价性。)
解密过程:使用私钥k计算Q = rkG 得到qx,qy。
m1 =  ((m1*qx) mod p)* qx^-1 mod p,
m2 = ((m2*qy)mod p)*qy^-1 mod p


7.算法实现

def ecadd(P, Q):                    #椭圆加法
    if P == (0, 0):                   #其中一个点是单位元的情况
        return Q
    if Q == (0, 0):
        return P

    (x1, y1) = P
    (x2, y2) = Q

    if x1 == x2 and y1 == y2:                              
        m = (3 * x1 * x1 + a) * pow(2 * y1, -1, p) % p         # P、Q重合的情况  切线斜率  
    else:
        m = (y2 - y1) * pow(x2 - x1, -1, p) % p                    # P ≠ Q

    x3 = (m * m - x1 - x2) % p
    y3 = (m * (x1 - x3) - y1) % p

    return (x3, y3)

def ec_mul(k, P):                                          #椭圆上的标量乘法,即一个整数乘以一个点,即K = kG ,倍点的计算
    R = (0, 0)
    for i in range(k.bit_length()):                     #使用二进制长度计算数值
        if (k >> i) & 1:
            R = ec_add(R, P)                               #k 个P 相加,即多次调用点的加法
        P = ec_add(P, P)
    return R

def generate_key_pair():                                 #生成密钥
    k = int.from_bytes(os.urandom(32), byteorder='big') % n                        #直接调用python库生成随机的私钥k,这里的n是所选曲线基点G的阶数。
    K = ec_mul(k, G)                                       #公钥K = kG
    return k, K

def encrypt(public_key, plaintext):                    #加密
    r = int.from_bytes(os.urandom(32), byteorder='big') % n                   #生成随机数 r
    C1 = ec_mul(r, G)                                                                           # 计算 C1 = rG    C1 = ec_mul(r, G)
    Q=ec_mul(r, K)                                                                                   # 获取 Q 的 x 坐标
    q_x = Q[0]
    q_y = Q[1]
    m1, m2 = plaintext
    m1_prime = (m1 * q_x) % p                                                            #对明文编码加密
    m2_prime = (m2 * q_y) % p
    return C1, m1_prime, m2_prime

def decrypt(private_key, C1, m1_prime, m2_prime):                               #解密过程,输入私钥,C1,密文1,密文2

    Q = ec_mul(private_key, C1)                                                            # 计算 Q = rK
    q_x = Q[0]                                                                                        # 获取 Q 的 x 坐标
    q_y = Q[1]                                                                                    
    q_x_inv = pow(q_x, -1, p)                                                                # 计算 q_x 的逆元
    q_y_inv = pow(q_y, -1, p)
    m1 = (m1_prime * q_x_inv) % p                                                      # 恢复 m1 = m1' * q_x^-1 % p
    m2 = (m2_prime * q_y_inv) % p                                                      # 恢复 m2 = m2' * q_x^-1 % p

    return m1, m2                           
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-22 19:19

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表