Binary Edwards曲线
题目:
from Crypto.Util.number import bytes_to_long
from flag import flag
assert flag[:5]=='*CTF{' and flag[-1]=='}'
flag=flag[5:-1]
def add(P,Q):
if Q==0:
return P
x1,y1=P
x2,y2=Q
return (d1*(x1+x2)+d2*(x1+y1)*(x2+y2)+(x1+x1^2)*(x2*(y1+y2+1)+y1*y2))/(d1+(x1+x1^2)*(x2+y2)),(d1*(y1+y2)+d2*(x1+y1)*(x2+y2)+(y1+y1^2)*(y2*(x1+x2+1)+x1*x2))/(d1+(y1+y1^2)*(x2+y2))
def mul(k,P):
Q=(0,0)
while k>0:
if is_even(k):
k/=2
P=add(P,P)
else:
k-=1
Q=add(P,Q)
return Q
F=GF(2**100)
R.<x,y>=F[]
d1=F.fetch_int(1)
d2=F.fetch_int(1)
x,y=(698546134536218110797266045394L, 1234575357354908313123830206394L)
G=(F.fetch_int(x),F.fetch_int(y))
P=mul(bytes_to_long(flag),G)
print (G[0].integer_representation(),G[1].integer_representation())
print (P[0].integer_representation(),P[1].integer_representation())
#(698546134536218110797266045394L, 1234575357354908313123830206394L)
#(403494114976379491717836688842L, 915160228101530700618267188624L)
解题思路:
分析曲线
-
我们首先分析一下这是个什么曲线,根据其形式判断其为二元域上的爱德华曲线(Binary Edwards)
-
其一般形式为

-
分析曲线结构
分析代码
**d1**
和**d2**
:这两个参数在椭圆曲线的加法和乘法操作中被使用,在代码中,d1
和d2
都被初始化为F.fetch_int(1)
,即在有限域GF(2<sup>100</sup>)
中的值为1
;它们在加法公式中作为系数,影响点的加法运算**F**
:是一个有限域GF(2<sup>100</sup>)
,表示一个大小为2<sup>100</sup>
的有限域,在这个域中,所有的运算都是模2<sup>100</sup>
的运算**x**
和**y**
:这是椭圆曲线上一个已知点G
的坐标,分别表示为长整数,程序通过F.fetch_int
将它们转换为有限域GF(2<sup>100</sup>)
中的元素**G**
:这是椭圆曲线上的一个基点,其坐标由x
和y
给出,程序通过mul
函数将flag
转换后的整数与基点G
相乘,得到加密后的点P
**P**
:这是加密后的点,是通过将flag
转换为整数后与基点G
相乘得到的结果,程序最后输出了P
的坐标
add(P,Q)
- 功能:实现椭圆曲线上两个点
<font style="color:rgb(6, 6, 7);">P</font>
和<font style="color:rgb(6, 6, 7);">Q</font>
的加法操作 - 参数:
P
和Q
是椭圆曲线上的两个点,每个点是一个二元组<font style="color:rgb(6, 6, 7);">(x,y)</font>
- 逻辑:
- 如果
<font style="color:rgb(6, 6, 7);">Q=0</font>
,返回<font style="color:rgb(6, 6, 7);">P</font>
,这里的<font style="color:rgb(6, 6, 7);">0</font>
表示椭圆曲线上的无穷远点 - 否则,计算
<font style="color:rgb(6, 6, 7);">P</font>
和<font style="color:rgb(6, 6, 7);">Q</font>
的坐标<font style="color:rgb(6, 6, 7);">(x1,y1)</font>
和<font style="color:rgb(6, 6, 7);">(x2,y2)</font>
- 根据椭圆曲线的加法规则,计算新的点
<font style="color:rgb(6, 6, 7);">R</font>
的坐标<font style="color:rgb(6, 6, 7);">(x3,y3)</font>
,这里的加法规则与常见的椭圆曲线加法有所不同,公式中包含了d1
和d2
作为系数,以及一些特殊的运算(如x1 + x1^2
)
- 如果
- 输出:返回新的点
<font style="color:rgb(6, 6, 7);">R</font>
的坐标<font style="color:rgb(6, 6, 7);">(x3,y3)</font>
mul(k,P)
- 功能:实现椭圆曲线上点
P
的标量乘法操作,即计算k×P
- 参数:
k
是一个整数,表示标量P
是椭圆曲线上的一个点
- 逻辑:
- 使用双倍加法算法来实现标量乘法
- 初始化
Q=(0,0)
,表示无穷远点 - 当
k>0
时:- 如果
k
是偶数,将P
加到自身(即P=P+P
),并将k
除以2
- 如果
k
是奇数,将P
加到Q
上(即Q=Q+P
),并将k
减1
- 如果
- 输出:返回最终的结果
Q
解密思路
-
换元映射
def f(P):
x,y = P
u = d1*(d1*d1 + d1 + d2)*(x + y) / (x*y + d1*(x+y))
v = d1*(d1*d1 + d1 + d2)*(x / (x*y + d1*(x+y)) + d1 + 1)
return EC(u, v)
- 然后利用椭圆曲线的离散对数算法求解标量
k
,使得P=k×G
解答:
F=GF(2**100)
d1=F.fetch_int(1)
d2=F.fetch_int(1)
x,y=(698546134536218110797266045394L, 1234575357354908313123830206394L)
G=(F.fetch_int(x),F.fetch_int(y))
#(698546134536218110797266045394L, 1234575357354908313123830206394L)
x,y = (403494114976379491717836688842L, 915160228101530700618267188624L)
P=(F.fetch_int(x),F.fetch_int(y))
a1 = F.fetch_int(1)
a3 = a4 = F.fetch_int(0)
a2 = d1**2 + d2
a6 = (d1**4)*(d1**4 + d1**2 + d2**2)
EC = EllipticCurve(F, [a1,a2,a3,a4,a6])
def f(P):
x,y = P
u = d1*(d1*d1 + d1 + d2)*(x + y) / (x*y + d1*(x+y))
v = d1*(d1*d1 + d1 + d2)*(x / (x*y + d1*(x+y)) + d1 + 1)
return EC(u, v)
order = EC.order()
P_ = f(P)
G_ = f(G)
x = discrete_log(P_, G_, operation="+")
print(bytes.fromhex(hex(x)[2:]))
#b'p01Y_Edw@rds'
#*CTF{p01Y_Edw@rds}