ECC 可是一个好玩的东西但是又好难!努力学习,学完就能开始学 pwn 了!(bushi x 这篇笔记里其实也没有太多东西 emmm, 就提到了 ECDLP 的部分内容吧... 可能相对应理解一些开始的概念得去看看《近世代数》什么的?前置最好在看看这篇 blog:https://www.cnblogs.com/Kalafinaian/p/7392505.html

# Ⅰ . Base Knowledge :

  • # 1 x 01: Elliptic Curve in Finite Field

    ECC 加密和 RSA,Diffie-Hellman 都是基于 trapdoor function 的公钥加密。

    • 对于 RSA, 陷门函数依赖于大数分解的困难
    • 对于 Diffie-Hellman, 陷门函数依赖于离散对数问题的困难
    • 对于 ECC, 由于 group operation 在生活中并不流行,因此很少会有人去学习,同时基于 再给出 Q 和 P 的情况下难以寻找到 n 使得 Q = n P

    Form : Y2=X3+aX+bmodqY^2=X^3+aX+b\mod q​ (Weierstrass 方程式)

    决定的曲线添加上无穷远的点,就可以得到射影平面P2(Fq)P^2(F_q) 上的一条曲线 E , 若非奇异曲线,且 Δ=4a3+27b20\Delta =4a^3+27b^2 ≠ 0 则称为一条椭圆曲线

    给定的一条 FqF_q 上的椭圆曲线 E ,以及任意两点 P 和 Q ,连接 P,Q 与 E 交于第三个点,这个点定义为 P ,Q 的和, 记作PQP\oplus Q,同时在加法定义下满足阿贝尔群

    加法定义下 特性:

    • P + O = O + P = P
    • P + (-P) = O
    • ( P + Q ) + R = P + ( Q + R )
    • P + Q = Q + R
  • # 1 x 02: Point Addition : P + Q

    先找到 P,Q 他们的 (x,y) 坐标,然后通过这两个点构成的直线找到与曲线的第三个焦点 R (x1,y1),同时存在一个点 R‘ (x1,-y1), 而这个 point addition 的结果就是 P+Q=R=R(x,y)P+Q=R'=R(x,-y) 而关于 ECC 的点加就是基于在 2D 空间内的,以及这个加了之后的点在趋向于无穷大

    **Algorithm : **

    • If P = O , then P + Q = Q
    • Otherwise, write P =(x1,y1)( x_1 , y_1 ) and Q = (x2,y2)(x_2 ,y_2)
      • if x1=x2x_1 = x_2 , y1=y2y_1 = -y_2 , then P + Q = O
      • Otherwise:
        • if P ≠ Q : $ λ = ( y_2 - y_1 )/( x_2 - x_1 )$
        • if P = Q : λ=(3x12+a)/(2y1)λ = (3x_1^2 + a )/(2y_1)
      • x3=λ2x1x2,y3=λ(x1x3)y1x_3 = λ^2 - x_1 - x_2 , y_3 = λ( x_1 - x_3 ) - y_1
      • P + Q = ( x3 , y3 )

    注:其中 div 里面如果我们不是用整数型去 divide 除他 ,我们反而乘以他的模逆

    e.g. 1 / 5 = 1*5^-1 mod(11)=1*9 mod 11=9

    exp:

    from Crypto.Util.number import*
    from gmpy2 import*
    def div(m,n,p):#其中的 /
        return m*inverse(n,p)
    def pointaddtion(P,Q,p):
        O=(0,0)
        if P[0]==O[0] and P[1]==O[1]:
            return Q
        elif Q[0]==O[0] and Q[1]==O[1]:
            return P
        elif Q[0]==P[0] and Q[1]==-P[0]:
            return O
        elif P!=Q:
            m=div(Q[1]-P[1],Q[0]-P[0],p)
        else:
            m=div(3*P[0]*P[0]+a,2*P[1],p)
        x3=m*m-Q[0]-P[0]
        y3=m*(P[0]-x3)-P[1]
        R=(x3%p,y3%p)
        return R
    a,b,p=497,1768,9739
    X=(5274,2841)
    Y=(8669,740)
    print(pointaddtion(X,X,p))
    print(pointaddtion(X,Y,p))
    #(7284, 2107)
    #(1024, 4440)
  • # 1 x 03 : Scalar Multiplication:

    Scalar Multiplication can be replaced by addtion: 3P=P+P+P3P=P+P+P .It always is used to create a shared secret over an inscure channel similarly to the Diffe-Hellman challenges.

    Algorithm:(input : P in E ( Fp) and an interger n >0 )

    • Set Q = P and R =O

    • loop:

      • while n>0:

        • if n1mod2n\equiv 1\ mod\ 2,setR=R+QR=R+Q

        • set tQ=2Q,n=n/2tQ=2Q,n=⌊n/2⌋

        • if n>0n>0,continue the loop

    • Return the poin RR , which equals nPnP.

    注:⌊⌋ 是 底角符号,意味着向下取整

    exp :

    from Crypto.Util.number import*
    from gmpy2 import*
    def div(m,n,p):#其中的 /
        return m*inverse(n,p)
    def pointaddtion(P,Q,p):
        O=(0,0)
        if P[0]==O[0] and P[1]==O[1]:
            return Q
        elif Q[0]==O[0] and Q[1]==O[1]:
            return P
        elif Q[0]==P[0] and Q[1]==-P[0]:
            return O
        elif P!=Q:
            m=div(Q[1]-P[1],Q[0]-P[0],p)
        else:
            m=div(3*P[0]*P[0]+a,2*P[1],p)
        x3=m*m-Q[0]-P[0]
        y3=m*(P[0]-x3)-P[1]
        R=(x3%p,y3%p)
        return R
    def scalarmultiplication(n,P,p):
        if n==1:
            return P
        Y=scalarmultiplication(n//2,P,p)
        X=pointaddtion(Y,Y,p)
        if n%2==1:
            X=pointaddtion(X,P,p)
        return X[0]%p,X[1]%p

    注意: 得到的点需要去检查是否在曲线上:

    def checkpoint(P,a,b,p):
     x,y=P
     right=(x*x*x+a*x+b)%p
     left=(y*y)%p
     if right==left:
         return 1
     else:
         return 0
  • # 1 x 04 : Curves and Logs

    椭圆曲线离散对数问题(ECDLP)是去寻找一个 n 使得 Q = nP. 就像 DLP 问题一样,点的标量乘法似乎也是一个困难的问题去解决,最有效的算法也需要跑 p**0.5 次数 这就导致他成为一个陷门函数

    加密过程

    • Alice 和 Bob 想要创造一种共享密钥,使得他们能够用一些对称加密的方式交换信息
    • Alice 和 Bob 都不相信传输环境,所以他们需要一个方式使得其他人不能破解
    • Alice 和 Bob 达成共识选择一个曲线 E,一个素数 p, 和一个 点 G
    • Alice 生成一个随机数 nA 计算 QA=nAGQ_A=n_A*G
    • Bob 生成一个随机数 nB 计算 QB=nBGQ_B=n_B*G
    • Alice 发QAQ_A 给 Bob,Bob 发QBQ_B 给 Alice. 基于 ECDLP 的困难,窥视者无法计算nAn_AnBn_B 在合理的时间内
    • Alice 计算 nAQBn_AQ_B , Bob 计算 nBQAn_BQ_A(基于 scalar multiplication 的可结合性,S=nAQB=nBQAS=n_AQ_B=n_BQ_A
    • Alice 和 Bob 即可用 s 作为他们的共享密钥

    注:密码学上的安全曲线需要 primes 的比特约等于 256

  • # 1 x 04 : Efficent Exchange

    为了使得数据传输更加快捷方便,同时发送公钥的 x 和 y 坐标是没有必要的。 只需要 Alice 和 Bob 统一一个曲线的限定,就只有两个可能性的 y 值对于一个已给出的 x

    注:在这些问题中,我们经常会使用一个素数p3mod4p\equiv\ 3\ mod \ 4

    这个可以帮助你在 y 的平方里找到 y 所以根据原根以及二次剩余可知当p3mod4p\equiv 3\mod 4y=pow(y2,(p+1)//4,p)y=pow(y^2,(p+1)//4,p)

  • # 1 x 05 : Ecc 中寻找基点的算法

    • 计算 椭圆曲线 E 的阶 N (#E)
    • 选择 一子群的阶为 n (n 为素数),辅因子 h=\frac{N}
    • 在 E 上随机选择一点 P , 如果 G=hp 为 0,则重新选取 P ,此时 G 为基点

# Ⅱ . ECDLP ATTACK :

ECDLP 是什么? 可以这样去理解它 ECC+DLP;那么上文中已经介绍过了 ECC 加密系统,接下来先回顾一下 DLP 离散对数问题

  • # 2 x 01.1 : Baby-Step,Giant - Step Algorithm ( 北上广深

    • 可以把他当作是一种中间相遇的思想,复杂度为 O(N)O(\sqrt{N})
    • 假设 αx=β\alpha^x=\beta ,G 是 n 阶循环群,令 m=int(N)+1m=int(\sqrt{N})+1 , 把 x 表示为 im+j(0i,jm)im+j(0≤i,j≤m) ,则有 β=αx=αim+j=αimαj\beta=\alpha^x=\alpha^{im+j}=\alpha^{im}\alpha^jβ(αm)i=αj\beta(\alpha^{-m})^i=\alpha^j , 先遍历j[0,m]j\in[0,m] 存储所有的αj\alpha^j, 再去遍历i[0,m]i\in[0,m] 找到碰撞即可
  • # 2 x 01.2 : Pollard's ρ -Method :

    • 和大数分解有类似之处,使用了 生日悖论
    • 假设 αx=β\alpha^x=\beta , G 是 n 阶循环群,再把他划分为 psize 个等价类, S1,S2...,SpsizeS_1,S_2,...,S_{psize} . 于是定义 G 上的序列 xi{x_i} , 每个xix_i 均能表示为 αaiβbi\alpha^{a_i}\beta^{b_i} ,并且去生成在有限域 FnF_n 上的随机序列 a , b (用一个 map 映射) ,函数如:g(x)=(xN1+3)modNg(x)=(x^{N-1}+3)\mod N 。所以直接推广,选取n\sqrt n 个数在之中两两比较,寻找到 iji-j 除 n ,即找到了 n 的 一个因子,就可以分解 n 了 ; 令初始值 x0x_0αax\alpha^{ax} (ax 随机),也可以表示为 a0=ax,b0=0a_0=ax,b_0=0 ,同时设y0=x0y_0=x_0 , 令 yi=x2iy_i=x_{2i} 则 我们有 αaxβbx=αayβby\alpha^{ax}\beta^{bx}=\alpha^{ay}\beta^{by} ,所以 αayax=(αres)bxby\alpha^{ay-ax}=(\alpha^{res})^{bx-by}GCD(bxby,n)=1GCD(bx-by,n)=1 时,存在逆元 所以 res=(bxby)1(ayax)res=(bx-by)^{-1}(ay-ax)
  • # 2 x 01.3 : Pollard's λ -Method:(kangaroo

    • 假设G(=ZP)G(=Z_P) 是 n 阶循环群,α,βG\alpha,\beta \in G , 满足 αx=β\alpha^x=\beta ,并且我们可以知道 x[a,b][0,p1]x\in[a,b]\sub[0,p-1]

      • l=ba,J=int(log2(l))l=b-a,J=int(\log_2*(l)) ,设 S=\{randrange(1,p),randrange(1,p),...randrange(1,p)\}=S\

      • 令 T 从已知起始点开始跳跃,设 t0=αbmodpt_0=\alpha^b\mod p,跳跃路径为:t(i+1)\equiv t(i)\alpha^

        让 T 在跳跃 n 次之后停止,并且 n 次后的跳跃指数 为:d(n)=Σt=0n1s(t(i)modJ)d(n)=\Sigma^{n-1}_{t=0}s(t(i)\mod J)

        因此 t(n)αb+d(n)modpt(n)\equiv \alpha^{b+d(n)}\mod p

      • W 的起始点 w0=αxw_0=\alpha^x , 则类似 T 有 D(j)=Σk=0j1s(w(k)modJ),D(0)=0,w(j)αx+D(j)modpD(j)=\Sigma^{j-1}_{k=0}s(w(k)\mod J),D(0)=0,w(j)\equiv \alpha^{x+D(j)}\mod p

      • 当碰撞发生在 t(i)=w(j)t(i)=w(j) 时,此点向后均 t(s)=w(r)(si=rj0).t(s)=w(r)\ (s-i=r-j≥0). 即有 αx+D(m)αb+d(n)modp\alpha^{x+D(m)}\equiv \alpha^{b+d(n)}\mod px=b+d(n)D(m)x=b+d(n)-D(m)

      ps: 跳跃步数 n 可以直接取做 int(ba)+1int(\sqrt{b-a})+1 将使 n 此后的碰撞概率趋向于 1,如果失败就重新求解

    • exp in sage

      '''sage'''
      from math import sqrt, log2, floor, ceil
      from Crypto.Util.number import *
      def pollard_lambda(beta, alpha, N):
          a, b = 0, N - 1
          l = N - 1
          J = floor(log2(l))
          n = ceil(sqrt(N))
          for i in tqdm(range(10)): #求解次数上限
              S = []
              for j in range(J):
                  r = getRandomRange(1, l)
                  S.append((r, pow(alpha, r, N)))
              # tame kangaroo T
              dt, t = b, pow(alpha, b, N)
              for j in range(n):
                  r, e = S[t % J]
                  dt += r
                  t = (t * e) % N
              # wild kangaroo W
              dw, w = 0, beta
              while dt - dw >= 0:
                  if w == t:
                      return dt - dw
                  r, e = S[w % J]
                  dw += r
                  w = (w * e) % N
          print("[-] Failed.")
          return None
  • # 2 x 01.4 : Pohlig-Hellman Method

    • G=Zmod(n),α,βGG=Zmod(n),\alpha,\beta\in G ,满足 αx=β\alpha ^x=\beta ,假设 α\alpha 的阶为 ord, 且可以表达为 ord=Πi=1kpiriord=\Pi^k_{i=1}p_i^{r_i} , 则对于 prp^r , 有 xx0+x1p+x2p2+...+xr1pr1modpr,0xip1x\equiv x_0+x_1p+x_2p^2+...+x_{r-1}p^{r-1}\mod p^r,0≤x_i≤p-1 . 变换得到 x(ordp)x0(ordp)+ordm,mZx(\frac{ord}{p})\equiv x_0(\frac{ord}{p})+ord·m,m\in Zβordpαx0(ordp)modn\beta^{\frac{ord}{p}}\equiv \alpha^{x_0(\frac{ord}{p})}\mod n ,在这里 x0x_0 只需要在 [0,p1][0,p-1] 上枚举。得到 x0x_0 之后 用类似的技巧求解 x1x_1 . 最后对所有结果 CRT 即可

    • exp :

      #!/usr/bin/env sage
      def bsgs(alpha, beta, modulus, upper_bound=None):
          if not upper_bound:
              upper_bound = Mod(alpha, modulus).multiplicative_order()
          m = ceil(sqrt(upper_bound))
          S = {pow(alpha, j, modulus):j for j in range(m + 1)}
          gs = Mod(alpha, modulus)^(-m)
          for i in range(m + 1):
              if beta in S:
                  return (i * m + S[beta])
              beta = (beta * gs) % modulus
          return None
      def pohlig_hellman(beta, alpha, N):
          beta, alpha = Mod(beta, N), Mod(alpha, N)
          ord = alpha.multiplicative_order()
          f = ord.factor()
          prime_order_mod = [0] * len(f)
          for i, (p, r) in enumerate(f):
              for j in range(r):
                  pmod = bsgs(alpha**(ord // p), (beta / alpha**prime_order_mod[i])**(ord // p**(j+1)), N, p - 1)
                  prime_order_mod[i] += pmod * (p**j)
          return crt(prime_order_mod, [p**r for (p, r) in f])
  • # 2 x 02: ECDLP ATTACK!

  • # 2 x 02.1 : BSGS

    • 已知 Q ,P ,阶 n,阶为 n 的基点 P 生成 E(Fp)E(F_p) ,且 QE(Fp)Q\in E(F_p) ,Q=kPQ=kPm=int(n)+1m=int(\sqrt{n})+1k=im+jk=im+j , 则可以得到 Q=kP=(im+j)P=imP+jPQ=kP=(im+j)P=imP+jP,可以得知 Qi(mP)=jPQ-i(mP)=jP , 与 BSGS 的 DLP 问题相似,建立一个j[0,m]j\in[0,m]jPjP 字典,然后取遍历 i 就可以碰撞得到 k 的值
  • # 2 x 02.2 : Pohilg -Hellman

    目前最有效的方法是将 Pohilg-Hellman 算法 和 Pollard's Rho 算法结合,需要的时间复杂度大概为O(p112)O(p_1^{\frac{1}{2}}) 其中 p1p_1 是阶数 n 的最大素因子,相应的为了对抗这种攻击,于是 ECC 的 n 都相对生成的参数都有大素因子或者本身就是大素因子。而其他的攻击手段是在曲线参数取值特殊的时候极大缩小复杂度的方法,比如说对 超椭圆曲线 有效的 MOV 方法,所以生成一个安全的椭圆曲线就要去绕过这些特殊情况。

    • Pohilg - Hellman 是为了解决离散对数问题提出的攻击方式,在 1978 年提出,主要思想是对阶数的分解,比如说整数域之中对 y=gxmodpy=g^x\mod p 求解 xx , 以及椭圆曲线 离散对数问题中 Gk = Q 中 G 的阶 n , 这样就把离散对数问题转移到了每个因子条件下对应的离散对数问题,于是就可以使用 CRT 求解

    • Pohilg-Hellman Algorithm in ECC

      1. 不妨设需要求解的式子为 Q=lPQ=lP (P 为选取的一个基点,l 是选定的随机数,即要求解的私钥
      2. 首先去求解得到 P 的阶 n (也就是让 n*P 不存在的最小正整数 n
      3. 分解 n 设 n=p1e1p2e2p3e3...prern=p_1^{e_1}p_2^{e_2}p_3^{e_3}...p_r^{e_r}​ 然后将这些因子拿出来 设i[1,r]i\in [1,r]
      4. 计算 l_i=l\mod p_i^
      5. 于是我们得到了下面一系列等式:l\equiv l_i\mod p_1^{e_1}\\\\l\equiv l_2\mod p_2^{e_2}\\\\...\\\\l\equiv l_r\mod p_2^
      6. 在这些式子中我们发现如果得到 l1,...lrl_1,...l_r 就可以通过 CRT 求解得到 ll
        1. 第一步先去把 lil_i 设成 pip_i 表示的多项式,如:l_i=z_0+z_1p_i+...+z_{e-1}p_i^
        2. z[0,pi1]z\in [0,p_i-1]​ ,去求解 z,我们分别取 P0=npiPP_0=\frac{n}{p_i}PQ0=npiQQ_0=\frac{n}{p_i}Q
        3. 因此 可知 piP0=nPp_iP_0=nP 于是得到 Q0=npiQ=npi(lP)=l(npiP)=lP0Q_0=\frac{n}{p_i}Q=\frac{n}{p_i}(lP)=l(\frac{n}{p_i}P)=lP_0
        4. lP0=Q0=>liP0=Q0=>(z0+z1pi+...+ze1pie1)P0=Q0=>z0P0=Q0lP_0=Q_0\\\\=>l_iP_0=Q_0\\\\=>(z_0+z_1p_i+...+z_{e-1}p_i^{e-1})P_0=Q_0\\\\=>z_0P_0=Q_0
        5. 这时,把 P 域上的离散对数分解到了 P0P_0 域上,因为 P0P_0 的阶为 npi\frac{n}{p_i} 因此复杂度小了很多
        6. (z0+z1pi+...+ze1pie1)P0=Q0=>z0P0+(z1pi+...+ze1pie1)P0=Q0=>(z1pi+...+ze1pie1)P0=Q0z0P0=>zipi=Q0z0P0(z_0+z_1p_i+...+z_{e-1}p_i^{e-1})P_0=Q_0\\\\=>z_0P_0+(z_1p_i+...+z_{e-1}p_i^{e-1})P_0=Q_0\\\\=>(z_1p_i+...+z_{e-1}p_i^{e-1})P_0=Q_0-z_0P_0\\\\=>z_ip_i=Q_0-z_0P_0
        7. 到这里就求出来了 z1z_1 然后依次求出 ziz_i 就得到了 l1l_1
      7. 求出所有的ll 以后 就可以使用 CRT 取得到 l
    • **Example : **( cryptohack 上的 Smooth Criminal

      from Crypto.Cipher import AES
      from Crypto.Util.number import inverse
      from Crypto.Util.Padding import pad, unpad
      from collections import namedtuple
      from random import randint
      import hashlib
      import os
      # Create a simple Point class to represent the affine points.
      Point = namedtuple("Point", "x y")
      # The point at infinity (origin for the group law).
      O = 'Origin'
      FLAG = b'crypto{??????????????????????????????}'
      def check_point(P: tuple):
          if P == O:
              return True
          else:
              return (P.y**2 - (P.x**3 + a*P.x + b)) % p == 0 and 0 <= P.x < p and 0 <= P.y < p
      def point_inverse(P: tuple):
          if P == O:
              return P
          return Point(P.x, -P.y % p)
      def point_addition(P: tuple, Q: tuple):
          # based of algo. in ICM
          if P == O:
              return Q
          elif Q == O:
              return P
          elif Q == point_inverse(P):
              return O
          else:
              if P == Q:
                  lam = (3*P.x**2 + a)*inverse(2*P.y, p)
                  lam %= p
              else:
                  lam = (Q.y - P.y) * inverse((Q.x - P.x), p)
                  lam %= p
          Rx = (lam**2 - P.x - Q.x) % p
          Ry = (lam*(P.x - Rx) - P.y) % p
      R = Point(Rx, Ry)
          assert check_point(R)
          return R
      def double_and_add(P: tuple, n: int):
          # based of algo. in ICM
          Q = P
          R = O
          while n > 0:
              if n % 2 == 1:
                  R = point_addition(R, Q)
              Q = point_addition(Q, Q)
              n = n // 2
          assert check_point(R)
          return R
      def gen_shared_secret(Q: tuple, n: int):
          # Bob's Public key, my secret int
          S = double_and_add(Q, n)
          return S.x
      def encrypt_flag(shared_secret: int):
          # Derive AES key from shared secret
          sha1 = hashlib.sha1()
          sha1.update(str(shared_secret).encode('ascii'))
          key = sha1.digest()[:16]
          # Encrypt flag
          iv = os.urandom(16)
          cipher = AES.new(key, AES.MODE_CBC, iv)
          ciphertext = cipher.encrypt(pad(FLAG, 16))
          # Prepare data to send
          data = {}
          data['iv'] = iv.hex()
          data['encrypted_flag'] = ciphertext.hex()
          return data
      # Define the curve
      p = 310717010502520989590157367261876774703
      a = 2
      b = 3
      # Generator
      g_x = 179210853392303317793440285562762725654
      g_y = 105268671499942631758568591033409611165
      G = Point(g_x, g_y)
      # My secret int, different every time!!
      n = randint(1, p)
      # Send this to Bob!
      public = double_and_add(G, n)
      print(public)
      # Bob's public key
      b_x = 272640099140026426377756188075937988094
      b_y = 51062462309521034358726608268084433317
      B = Point(b_x, b_y)
      # Calculate Shared Secret
      shared_secret = gen_shared_secret(B, n)
      # Send this to Bob!
      ciphertext = encrypt_flag(shared_secret)
      print(ciphertext)

      以及一个附件

      Point(x=280810182131414898730378982766101210916, y=291506490768054478159835604632710368904)

      观察可知他在这里是使用了 shared secret 的 x 作为公共密钥 去加密,并且 G 的 order 是一个光滑的数,于是我们可以使用 Pohlig-Hellman Algorithm

      sagemath 在这里体现出他属实牛啊。(但不是原理有 p 用。只不过当个工具解题???还是多去考虑考虑原理吧

      一开始我们就是先去求解得到基点 G 的阶 n , 然后去分解

      '''#sage
      # Define the curve
      p = 310717010502520989590157367261876774703
      a = 2
      b = 3
      # Generator
      g_x = 179210853392303317793440285562762725654
      g_y = 105268671499942631758568591033409611165
      F = FiniteField(p)
      E = EllipticCurve(F,[a,b])
      G = E.point((g_x, g_y))
      n = G.order()
      n.factor()#2 * 3^7 * 139 * 165229 * 31850531 * 270778799 * 179317983307
      primes = [2,3^7, 139 , 165229 , 31850531 , 270778799 , 179317983307]
      x=280810182131414898730378982766101210916
      y=291506490768054478159835604632710368904
      C = E.point((x, y))
      dlogs = []
      for fac in primes:
          t = int( n // fac )
          dlog = discrete_log( t*C , t*G, operation='+' )
          dlogs += [dlog]
          print("factor:"+str(fac)+",Discrete Log:"+str(dlog))
      nC = crt(dlogs,primes)#47836431801801373761601790722388100620
      b_x = 272640099140026426377756188075937988094
      b_y = 51062462309521034358726608268084433317
      B = E.point((b_x, b_y))
      SS = nC*B#(171172176587165701252669133307091694084 : 188106434727500221954651940996276684440 : 1)
      '''
      from Crypto.Util.number import*
      from Crypto.Cipher import AES
      import hashlib
      iv=0x07e2628b590095a5e332d397b8a59aa7
      iv = long_to_bytes(iv)
      encrypted_flag=0x8220b7c47b36777a737f5ef9caa2814cf20c1c1ef496ec21a9b4833da24a008d0870d3ac3a6ad80065c138a2ed6136af
      c = long_to_bytes(encrypted_flag)
      sha1 = hashlib.sha1()
      shared_secret=171172176587165701252669133307091694084
      sha1.update(str(shared_secret).encode('ascii'))
      key = sha1.digest()[:16]
      cipher = AES.new(key, AES.MODE_CBC, iv)
      flag = cipher.decrypt(c)
      print(flag)

请我喝[茶]~( ̄▽ ̄)~*

De3B4to 微信支付

微信支付

De3B4to 支付宝

支付宝