isogeny

感觉大家都会同源,就我不会,花了两天的时间对着鸡块bloghuangx607087学习了一下

数学基础

超奇异椭圆曲线

对于有限域 GF(pr)GF(p^r) 下的椭圆曲线 EE 其的阶 OO 满足 1Omodp1\equiv O\mod p 那么称 EE 为超奇异曲线。

1
2
3
4
5
6
7
p = 283
E = EllipticCurve(GF(p ^ 2, name="i", modulus=[1, 0, 1]), [1, 0])
print(E.order() % p == 1, E.is_supersingular())
# True True
E = EllipticCurve(GF(p ^ 2, name="i", modulus=[1, 0, 1]), [1, 1])
print(E.order() % p == 1, E.is_supersingular())
# False False

一般来说,超奇异椭圆曲线是在 GF(p2)GF(p^2) 下工作的,所以满足 p%4=3p\%4=3

j-不变量

对于有限域 GF(pr)GF(p^r) 下的椭圆曲线 E:y2=x3+ax+bE:y^2=x^3+ax+b,我们定义其的的j-不变量:

j=1728(4a)3Δj=\frac{1728(4a)^3}{-\Delta}

其中 Δ=16(4a3+27b2)\Delta=-16(4a^3+27b^2),若 Δ=0\Delta=0 时,该曲线为奇异曲线不存在j-不变量。

1
2
3
4
5
6
7
8
9
10
from Crypto.Util.number import getPrime

p = getPrime(256)
a = getRandomRange(1, p)
b = getRandomRange(1, p)
E = EllipticCurve(GF(p), [a, b])
j1 = E.j_invariant()
Δ = -16 * (4 * a ^ 3 + 27 * b ^ 2)
j2 = 1728 * (4 * a) ^ 3 * inverse_mod(-Δ, p) % p
assert j1 == j2

如果两条曲线的j-不变量相同,则两条曲线同构,即存在映射:

ϕ:E1(x,y)E2(x,y)\phi:E_1(x,y)\mapsto E_2(x',y')

对于 GF(4180512)GF(418051^2) 下的椭圆曲线 E1:y2=x3+x+1,E2:y2=x3+146258x+405280E_1:y^2 = x^3 + x + 1,E_2:y^2 = x^3 + 146258*x + 405280 存在映射:

ϕ:E1(x,y)E2(122373x,206462y)\phi:E_1(x,y)\mapsto E_2(-122373x,-206462y)

可以使用sage计算

1
2
3
4
5
6
7
8
9
10
11
p = 418051
R.<i> = GF(p ^ 2, name="i", modulus=[1, 0, 1])
E1 = EllipticCurve(R, [1, 1])
E2 = EllipticCurve(R, [146258, 405280])
assert E1.j_invariant() == E2.j_invariant()
assert E1.is_isomorphic(E2)
phi = E1.isomorphism_to(E2)
phi.rational_maps()
# (-122373*x, -206462*y)
G = E1.random_point()
E2([-122373*G[0], -206462*G[1]])

而对于任意的p,其上面超奇异椭圆曲线j-不变量的个数为 p12+z\lfloor\frac{p}{12}\rfloor+z,其中 zz 的取值为1,2,3。

下图为当 p=431p=431 时在GF(p2)GF(p^2)上超奇异椭圆曲线j-不变量的个数

image-20250204174528599

Montgomery Curve

我们在ECC中常用的曲线形式一般都为 Short Weierstrass curvesy2=x3+ax+by^2=x^3+ax+b,而 Montgomery Curve 的形式为 y2=x3+Ax2+xy^2=x^3+Ax^2+x。对于任意一条 Short Weierstrass curves 都可以映射为 Montgomery Curve

1
2
3
4
5
p = 418051
R.<i> = GF(p ^ 2, name="i", modulus=[1, 0, 1])
E1 = EllipticCurve(R, [1, 1])
E1.montgomery_model()
# Elliptic Curve defined by y^2 = x^3 + 398605*i*x^2 + x over Finite Field in i of size 418051^2

对于 Montgomery Curve 而言其得j-不变量的计算方式为

j=256(A23)3A24j=\frac{256(A^2-3)^3}{A^2-4}

同源

概念

相较于ECC点对点的运算,同源可以相当于两条曲线之前的映射关系,其实前面在里面也已经提到过了。举一个简单的例子,将一条曲线对自己的二倍点进行映射

1
2
3
4
5
6
p = 418051
R.<i> = GF(p ^ 2, name="i", modulus=[1, 0, 1])
E = EllipticCurve(R, [1, 0])
phi = E.scalar_multiplication(2)
print(phi.rational_maps())
# ((x^4 - 2*x^2 + 1)/(4*x^3 + 4*x), (8*x^6*y + 40*x^4*y - 40*x^2*y - 8*y)/(64*x^6 + 128*x^4 + 64*x^2))

可以得到映射为

ϕ:(x,y)(x42x2+14x3+4x,x6y+5x4y5x2yy8x6+16x4+8x2)\phi:(x,y)\mapsto \left(\frac{x^{4} - 2 x^{2} + 1}{4 x^{3} + 4 x}, \frac{x^{6} y + 5 x^{4} y - 5 x^{2} y - y}{8 x^{6} + 16 x^{4} + 8 x^{2}}\right)

当然,我们可以令 4x3+4x=04 x^{3} + 4 x=0,可以得到 [0,i,i][0,i,-i]​,也就相当于实现了division_points

1
2
E(0).division_points(2)
# [(0 : 1 : 0), (0 : 0 : 1), (i : 0 : 1), (418050*i : 0 : 1)]

同样的,其也可以对自己的四倍点进行映射

1
2
3
phi = E.scalar_multiplication(2)
print(phi.rational_maps())
E(0).division_points(4)

可以得到

ϕ:(x,y)(x1640x14+348x12+1000x10+1478x8+1000x6+348x440x2+116x15+176x13+400x11592x9592x7+400x5+176x3+16x,32x24y+2176x22y54208x20y104832x18y+208870x16y+62991x14y+160405x12y+62991x10y+208870x8y104832x6y54208x4y+2176x2y+32y2048x24+34816x22+186368x20198915x18+168454x16+102918x14102918x12168454x10+198915x8186368x634816x42048x2)\phi:(x,y)\mapsto \left(\frac{x^{16} - 40 x^{14} + 348 x^{12} + 1000 x^{10} + 1478 x^{8} + 1000 x^{6} + 348 x^{4} - 40 x^{2} + 1}{16 x^{15} + 176 x^{13} + 400 x^{11} - 592 x^{9} - 592 x^{7} + 400 x^{5} + 176 x^{3} + 16 x}, \frac{32 x^{24} y + 2176 x^{22} y - 54208 x^{20} y - 104832 x^{18} y + 208870 x^{16} y + 62991 x^{14} y + 160405 x^{12} y + 62991 x^{10} y + 208870 x^{8} y - 104832 x^{6} y - 54208 x^{4} y + 2176 x^{2} y + 32 y}{2048 x^{24} + 34816 x^{22} + 186368 x^{20} - 198915 x^{18} + 168454 x^{16} + 102918 x^{14} - 102918 x^{12} - 168454 x^{10} + 198915 x^{8} - 186368 x^{6} - 34816 x^{4} - 2048 x^{2}}\right)

总的来说,对于阶为 ll 的点,我们称为 ll-torsion。

因此一个可分的同源可以描述为:对于曲线E和其的一个子群 GG,都可以构造一个以 GG 为核的映射 ϕ:E1(x,y)E2(x,y)\phi:E_1(x,y)\mapsto E_2(x',y'),我们称这个映射为同源,而曲线 E2E_2 为其的陪域。

sage上的实现

当然,在sage上同源有很好的实现

我们选择 (350i+68,0)(350i + 68,0) 来计算同源

1
2
3
4
5
6
7
8
9
p = 431
R.<i> = GF(p ^ 2, name="i", modulus=[1, 0, 1])
E = EllipticCurve(R, [0, 161+208*i, 0, 1, 0])
G = E(350*i + 68,0)
phi = E.isogeny(G)
phi.codomain()
# Elliptic Curve defined by y^2 = x^3 + (208*i+161)*x^2 + (343*i+209)*x + (363*i+398) over Finite Field in i of size 431^2
phi.rational_maps()
# ((x^2 + (81*i - 68)*x + (190*i - 214))/(x + (81*i - 68)), (x^2*y + (162*i - 136)*x*y + y)/(x^2 + (162*i - 136)*x + (190*i - 213)))

我们可以注意到同源得到的曲线的j-不变量和原曲线不同,所以同源并不是同构,而同构可以算是同源的一种特殊情况。

性质

一条曲线一个子群只能唯一对应一个同源

同源是同态的,即有 ϕ(P+Q)=ϕ(P)+ϕ(Q)\phi(P+Q)=\phi(P)+\phi(Q)

同源是对偶的

同源图

可以发现我们选择的 (350i+68,0)(350i + 68,0)22-torsion 的点,其映射后的j-不变量发生了变换:

364i+304344i+190364i + 304\mapsto 344i + 190

而在 22-torsion 还有其它的点,我们将其都进行同源的话可以得到如下j-不变量:

364i+30467364i+304319364i + 304\mapsto 67\\ 364i + 304\mapsto 319

而如果我们以E的j-不变量为起点,将映射得到的曲线的j-不变量视为终点。然后持续这么做把所有点的 22-torsion 都画出来,就可以得到完整的22-torsion 的同源图

image-20250204181517145

而同源是对偶的,所以同源图图也是无向图。

modular polynomial

https://math.mit.edu/~drew/ClassicalModPolys.html

SIDH

算法实现

首先要选取类似如下形式的质数p

p=2ea3eb1p=2^{e_a}3^{e_b}-1

然后在其二次扩域下定义曲线 E0:y2=x3+ax2+xE_0:y^2=x^3+ax^2+x

Alice在 E0E_0 中要选择两个阶为 2ea2^{e_a} 的点 (P2,Q2)(P_2,Q_2),Bob在 E0E_0 中要选择两个阶为 3eb3^{e_b} 的点 (P3,Q3)(P_3,Q_3),这些点和 E0E_0 均为公共参数

只后Alice和Bob要分别选择自己的私钥 sA,sBs_A,s_B

对于公钥生成,Alice需计算 KA=P2+sAQ2K_A=P_2+s_AQ_2,然后计算 E0E_0KAK_A 产生的同源 ϕA\phi_A,计算 ϕA(P3),ϕA(Q3)\phi_A(P_3),\phi_A(Q_3)。公钥为(ϕA,ϕA(P3),ϕA(Q3)\phi_A,\phi_A(P_3),\phi_A(Q_3))

而Bob则计算 KB=P3+sBQ3K_B=P_3+s_BQ_3,然后计算 E0E_0KBK_B 产生的同源 ϕB\phi_B,计算 ϕB(P2),ϕB(Q2)\phi_B(P_2),\phi_B(Q_2)。公钥为(ϕB,ϕB(P2),ϕB(Q2)\phi_B,\phi_B(P_2),\phi_B(Q_2))

对于共享密钥,Alice计算KSA=ϕB(P2)+sAϕB(Q2)K_{SA}=\phi_B(P_2)+s_A\phi_B(Q_2),然后计算 EBE_BKSAK_{SA} 产生的同源 ϕSA\phi_{SA},Bob计算KSB=ϕA(P3)+sBϕA(Q3)K_{SB}=\phi_A(P_3)+s_B\phi_A(Q_3),然后计算 EAE_AKSBK_{SB} 产生的同源,最后有j(ϕSA)=j(ϕSB)j(\phi_{SA})=j(\phi_{SB}),也就是同源得到的曲线的j-不变量作为共享密钥。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
ea, eb = 110, 67
p = 2**ea*3**eb - 1
F.<i> = GF(p**2, modulus=[1,0,1])

E0 = EllipticCurve(F, [1,0])
# public parameters
P2 = E0(118242575052254473701407051403380184157502700009529430046122822477*i + 57638278144985143549644316704182130279784191379170896458696787312, 80915735815367072410310689908590367651933218830435520913424043510*i + 35228327576503752484578273317308597612913304063200715424014549037)
Q2 = E0(27856673727210297071672501895829918842041821446996051944738115273*i + 101349537690838191347553037323956940169953967852439843389873653018, 45955772915614774101614751673022340983778200451506382887743008335*i + 76499786039494489791183573966490259392789635716963920208794989512)
P3 = E0(68702305424425607424554396971378391833152415806389206440833676844*i + 63162905189208938201083385603424075109355856156240516441321158383, 14452401602439328239712793251073780692192036710425129093829067649*i + 110903430163815016394569999096524527007769669322432532390635606190)
Q3 = E0(50967992419888058158544483269655763559879646024537212566396940681*i + 39165103284419354968504615023980382940222714919046676966425620242, 113476160032430656302485251779124302915433268423829474022852380544*i + 74814862075401178218909769629701747112662266906635780085603780902)

# Secret Keys
sA = 225902606209514408534212339057054
sB = 38410379124791756271891302485727

def gen_public_key(P2,Q2,P3,Q3,s):
KA = P2+s*Q2
phiA = E0.isogeny(KA,algorithm="factored")
EA = phiA.codomain()
return EA,phiA(P3),phiA(Q3)

def gen_shared_secret(EB,pb2,qb2,sA):
KSA = pb2+sA*qb2
phiSA = EB.isogeny(KSA,algorithm="factored")
return phiSA.codomain().j_invariant()

# public key
EA,pa3,qa3 = gen_public_key(P2,Q2,P3,Q3,sA)
EB,pb2,qb2 = gen_public_key(P3,Q3,P2,Q2,sB)

# shared secret
s1 = gen_shared_secret(EB,pb2,qb2,sA)
s2 = gen_shared_secret(EA,pa3,qa3,sB)
assert s1==s2
s1

attack

SIDH在2022年就已经完蛋了XD

Castryck-Decru-SageMath 就有对SIDH的攻击方式