一、ECC曲线参数

ECC方程

素数域上的短 Weierstrass 曲线通常写为:

$E(\mathbb F_p):\quad y^2\equiv x^3+ax+b\pmod p$

常见参数如下:

必须注意:

  • p域模数n基点所在子群的阶,二者不能混用。

  • h = 1 时,通常有$ \#E(\mathbb F_p)=n。$

  • 未压缩点编码一般为 04 || Gx || Gy;开头的 04 不是坐标的一部分。

  • Curve25519、Ed25519 使用不同曲线模型,不能直接套用短 Weierstrass 的 a, b

常用曲线速查


secp256k1

曲线方程:$y^2=x^3+7\pmod p$

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
p = int(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
"FFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",
16
)
a = 0
b = 7

Gx = int(
"79BE667EF9DCBBAC55A06295CE870B07"
"029BFCDB2DCE28D959F2815B16F81798",
16
)
Gy = int(
"483ADA7726A3C4655DA4FBFC0E1108A8"
"FD17B448A68554199C47D08FFB10D4B8",
16
)

n = int(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE"
"BAAEDCE6AF48A03BBFD25E8CD0364141",
16
)
h = 1

辨识特征:a = 0, b = 7。它是区块链和 CTF 中最常见的曲线之一。


secp256r1 / NIST P-256 / prime256v1

这三个名称通常表示同一条曲线。曲线方程为:$y^2=x^3-3x+b\pmod p$

由于有限域中 -3 也可以写成 p - 3,所以下面的 a 是一个很大的正整数。

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
p = int(
"FFFFFFFF000000010000000000000000"
"00000000FFFFFFFFFFFFFFFFFFFFFFFF",
16
)
a = int(
"FFFFFFFF000000010000000000000000"
"00000000FFFFFFFFFFFFFFFFFFFFFFFC",
16
)
b = int(
"5AC635D8AA3A93E7B3EBBD55769886BC"
"651D06B0CC53B0F63BCE3C3E27D2604B",
16
)

Gx = int(
"6B17D1F2E12C4247F8BCE6E563A440F2"
"77037D812DEB33A0F4A13945D898C296",
16
)
Gy = int(
"4FE342E2FE1A7F9B8EE7EB4A7C0F9E16"
"2BCE33576B315ECECBB6406837BF51F5",
16
)

n = int(
"FFFFFFFF00000000FFFFFFFFFFFFFFFF"
"BCE6FAADA7179E84F3B9CAC2FC632551",
16
)
h = 1

secp384r1 / NIST P-384

曲线形式仍为$y^2=x^3-3x+b\pmod p$

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
36
37
38
39
p = int(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE"
"FFFFFFFF0000000000000000FFFFFFFF",
16
)
a = int(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE"
"FFFFFFFF0000000000000000FFFFFFFC",
16
)
b = int(
"B3312FA7E23EE7E4988E056BE3F82D19"
"181D9C6EFE8141120314088F5013875A"
"C656398D8A2ED19D2A85C8EDD3EC2AEF",
16
)

Gx = int(
"AA87CA22BE8B05378EB1C71EF320AD74"
"6E1D3B628BA79B9859F741E082542A38"
"5502F25DBF55296C3A545E3872760AB7",
16
)
Gy = int(
"3617DE4A96262C6F5D9E98BF9292DC29"
"F8F41DBD289A147CE9DA3113B5F0B8C0"
"0A60B1CE1D7E819D7A431D7C90EA0E5F",
16
)

n = int(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
"FFFFFFFFFFFFFFFFC7634D81F4372DDF"
"581A0DB248B0A77AECEC196ACCC52973",
16
)
h = 1

secp521r1 / NIST P-521

P-521 是 521 位曲线,不是 512 位。其域素数具有简洁形式:$p=2^{521}-1$

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
36
37
p = 2**521 - 1
a = p - 3
b = int(
"0051953EB9618E1C9A1F929A21A0B685"
"40EEA2DA725B99B315F3B8B489918EF1"
"09E156193951EC7E937B1652C0BD3BB1"
"BF073573DF883D2C34F1EF451FD46B50"
"3F00",
16
)

Gx = int(
"00C6858E06B70404E9CD9E3ECB662395"
"B4429C648139053FB521F828AF606B4D"
"3DBAA14B5E77EFE75928FE1DC127A2FF"
"A8DE3348B3C1856A429BF97E7E31C2E5"
"BD66",
16
)
Gy = int(
"011839296A789A3BC0045C8A5FB42C7D"
"1BD998F54449579B446817AFBD17273E"
"662C97EE72995EF42640C550B9013FAD"
"0761353C7086A272C24088BE94769FD1"
"6650",
16
)

n = int(
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
"FA51868783BF2F966B7FCC0148F709A5"
"D03BB5C9B8899C47AEBB6FB71E913864"
"09",
16
)
h = 1

SM2 推荐曲线 / sm2p256v1

SM2 使用 256 位素数域短 Weierstrass 曲线,可用于公钥加密、签名和密钥交换。

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
p = int(
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF"
"FFFFFFFF00000000FFFFFFFFFFFFFFFF",
16
)
a = int(
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF"
"FFFFFFFF00000000FFFFFFFFFFFFFFFC",
16
)
b = int(
"28E9FA9E9D9F5E344D5A9E4BCF6509A7"
"F39789F515AB8F92DDBCBD414D940E93",
16
)

Gx = int(
"32C4AE2C1F1981195F9904466A39C994"
"8FE30BBFF2660BE1715A4589334C74C7",
16
)
Gy = int(
"BC3736A2F4F6779C59BDCEE36B692153"
"D0A9877CC62A474002DF32E52139F0A0",
16
)

n = int(
"FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF"
"7203DF6B21C6052B53BBF40939D54123",
16
)
h = 1

辨识特征:pFFFFFFFE 开头,且 a = p - 3


brainpoolP256r1

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
p = int(
"A9FB57DBA1EEA9BC3E660A909D838D72"
"6E3BF623D52620282013481D1F6E5377",
16
)
a = int(
"7D5A0975FC2C3057EEF67530417AFFE7"
"FB8055C126DC5C6CE94A4B44F330B5D9",
16
)
b = int(
"26DC5C6CE94A4B44F330B5D9BBD77CBF"
"958416295CF7E1CE6BCCDC18FF8C07B6",
16
)

Gx = int(
"8BD2AEB9CB7E57CB2C4B482FFC81B7AF"
"B9DE27E1E3BD23C23A4453BD9ACE3262",
16
)
Gy = int(
"547EF835C3DAC4FD97F8461A14611DC9"
"C27745132DED8E545C1D54C72F046997",
16
)

n = int(
"A9FB57DBA1EEA9BC3E660A909D838D71"
"8C397AA3B561A6F7901E0E82974856A7",
16
)
h = 1

Curve25519 / X25519

Curve25519 使用 Montgomery 模型:$v^2=u^3+486662u^2+u\pmod p$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
p = 2**255 - 19
A = 486662
# Montgomery ladder 常用常数:(A - 2) // 4
a24 = 121665

# RFC 7748 指定的基点
Gu = 9
Gv = int(
"147816194475895447910205935684099868872646061346164752889648818"
"37755586237401"
)
# 素数阶子群的阶
n = 2**252 + int("14DEF9DEA2F79CD65812631A5CF5D3ED", 16)
h = 8

这里要区分:

  • Curve25519:曲线本身。

  • X25519:在该曲线上定义的 Diffie–Hellman 标量乘函数。

  • X25519 对外通常只处理 u 坐标,输入输出是 32 字节小端序,不能把它当作 SEC1 的 04 || x || y 点编码。

  • X25519 标量还需要按 RFC 7748 进行 clamping(位掩码处理)。


edwards25519 / Ed25519

Ed25519 使用 twisted Edwards 曲线:$-x^2+y^2=1+dx^2y^2\pmod p$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
p = 2**255 - 19
d = int(
"370957059346694393431380835087545651895421138798432190163887855330"
"85940283555"
)

Gx = int(
"151122213495354007725011514095885315114540126930418572060461132"
"83949847762202"
)
Gy = int(
"463168356949264781694283940034751631413079938662562256157830336"
"03165251855960"
)

n = 2**252 + int("14DEF9DEA2F79CD65812631A5CF5D3ED", 16)
h = 8

注意:

  • edwards25519 是曲线;Ed25519 是定义在该曲线上的 EdDSA 签名方案。

  • Ed25519 主要用于签名,不是公钥加密算法。

  • 编码点时通常编码 y 的小端序,并把 x 的奇偶位放入最高位;不能直接使用 SEC1 未压缩点格式。


Curve448 / X448 与 Ed448

11.1 Curve448 / X448

Montgomery 形式:$v^2=u^3+156326u^2+u\pmod p$

1
2
3
4
5
6
7
8
9
10
11
p = 2**448 - 2**224 - 1
A = 156326
a24 = (A - 2) // 4 # 39081
Gu = 5

n = 2**446 - int(
"8335DC163BB124B65129C96FDE933D8D"
"723A70AADC873D6D54A7BB0D",
16
)
h = 4

X448 的输入输出是 56 字节小端序

11.2 edwards448 / Ed448

Ed448 使用的 Edwards 曲线为:$x^2+y^2=1-39081x^2y^2\pmod p$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
p = 2**448 - 2**224 - 1
d = -39081 % p

Gx = int(
"224580040295924300187604334099896036246789641632564134246125461"
"686950415467406032909029192869357953282578032075146446173674602635"
"247710"
)
Gy = int(
"298819210078481492676017930443930673437544040154080242095928241"
"372331506189835876003536878655418784733982303233503462500531545062"
"832660"
)

n = 2**446 - int(
"8335DC163BB124B65129C96FDE933D8D"
"723A70AADC873D6D54A7BB0D",
16
)
h = 4

二、解题

SageMath 通用模板

对于 secp256k1、P-256、P-384、P-521、SM2、Brainpool 等短 Weierstrass 曲线:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from sage.all import *

# 先粘贴相应曲线的 p, a, b, Gx, Gy, n, h
F = GF(p)
E = EllipticCurve(F, [a, b])
G = E(Gx, Gy)

assert G in E
assert n * G == E(0) # 无穷远点
assert G.order() == n

# 示例:生成私钥和公钥
d = ZZ.random_element(1, n)
Q = d * G
print("private =", d)
print("public =", Q)

若只想快速检查基点是否在曲线上:

1
assert (Gy*Gy - (Gx**3 + a*Gx + b)) % p == 0

Curve25519 和 Ed25519 的模型不同,SageMath 写法分别是:

1
2
3
4
5
6
7
8
9
from sage.all import *

# Curve25519:v^2 = u^3 + A*u^2 + u
p = 2**255 - 19
F = GF(p)
E_mont = EllipticCurve(F, [0, 486662, 0, 1, 0])

# edwards25519 更适合直接按 Edwards 加法公式实现,
# 或使用专门支持 Edwards 曲线/Ed25519 的密码库。

CTF 解题技巧

常见攻击面:

  • n 光滑:Pohlig–Hellman;

  • 曲线阶等于 p:Smart Attack;

  • embedding degree 小:MOV Attack;

  • 点验证缺失:Invalid Curve / Small Subgroup Attack;

  • ECDSA nonce k 复用:直接恢复私钥;

  • nonce 偏置或部分比特泄露:HNP / Lattice;

  • 自定义曲线、异常小参数:BSGS、Pollard rho 或直接离散对数;

  • 只泄露坐标的部分比特:格、Coppersmith 或枚举补全。

推荐分析链:

$\boxed{ \text{识别模型}\rightarrow \text{核对参数}\rightarrow \text{检查点与阶}\rightarrow \text{检查 nonce}\rightarrow \text{选择 ECDLP/代数攻击} }$

OpenSSL 查看标准曲线参数

列出本机支持的曲线:

1
openssl ecparam -list_curves

查看显式参数:

1
2
3
4
5
6
openssl ecparam -name secp256k1 -param_enc explicit -text -noout
openssl ecparam -name prime256v1 -param_enc explicit -text -noout
openssl ecparam -name secp384r1 -param_enc explicit -text -noout
openssl ecparam -name secp521r1 -param_enc explicit -text -noout
openssl ecparam -name SM2 -param_enc explicit -text -noout
openssl ecparam -name brainpoolP256r1 -param_enc explicit -text -noout

OpenSSL 输出中:

  • Prime 对应 p

  • A, B 对应曲线系数;

  • Generator 的首字节 04 是未压缩点标志,后面才是 Gx || Gy

  • Order 对应 n

  • Cofactor 对应 h

  • 多出来的前导 00 通常只是为了把 ASN.1 整数表示为正数,转换为整数时可去掉。


标准资料


速查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
secp256k1   y² = x³ + 7                  Bitcoin / Ethereum / CTF
P-256 y² = x³ - 3x + b TLS / ECDSA / ECDH
P-384 384 位,约 192-bit 安全 高安全 TLS / PKI
P-521 p = 2^521 - 1256-bit 安全
SM2 256 位国密曲线 加密 / 签名 / 密钥交换
X25519 Montgomery,u=9 密钥交换
Ed25519 twisted Edwards 数字签名
X448 Montgomery,u=5224-bit 密钥交换
Ed448 Edwards,d=-39081224-bit 签名

p 有限域模数
a, b 曲线系数
G 基点
n G 的阶,nG = O
h 余因子,#E = n*h
Q = dG 公钥