Private Key Tools

压缩公钥 → 曲线点、hash160、地址

把 33 字节公钥解压回完整的曲线点:从 X 还原 Y、验证它确实落在 secp256k1 上,再做哈希并编码成 P2PKH、P2SH-P2WPKH、P2WPKH 与 P2TR 地址。同一个点的非压缩形式会并排显示,因为它会产出另一个地址 —— 而整个过程完全不使用私钥。

66 位十六进制:02(Y 为偶)或 03(Y 为奇)后跟 32 字节 X 坐标。允许 0x 前缀与空格。这类字符串里大约有一半不是合法的曲线点,会在曲线方程校验后被拒绝。
还没有输入

请在上方输入内容后点击「转换」。不知道填什么?点「填入示例」即可载入占位符里的演示数据。

技术原理详解

本页计算了什么

你给它一个压缩公钥 —— 66 位十六进制、以 02 或 03 开头 —— 它会做钱包每次加载地址时都要做的两件事:把公钥解压回完整的曲线点,验证这个点确实落在 secp256k1 上,然后把它的哈希编码成它能生成的所有地址类型。整个过程与本页任何地方都不涉及私钥,也根本 不需要私钥。

已知 X 与一个奇偶位:  Y = (X³ + 7)(p+1)/4 mod p  再按所需奇偶性取反
02/03 ‖ X→ 解 Y² = X³+7→ 点 (X, Y)→ 曲线方程校验→ hash160→ Base58Check / Bech32 / Bech32m

本页还会显示同一个点的非压缩序列化形式,以及由它得到的另一个地址,因为 压缩/非压缩的区别正是比特币里「钱包显示余额不对」这类困惑最常见的来源。

1. 02/03 前缀就是一个奇偶位

公钥是素域 p 上曲线 y² = x³ + 7 的一个点 (X, Y)。老实存储它要 花 64 字节。2012 年整个生态改成了只存 X 加一个比特,因为 Y 可以被精确地重算 出来。那个比特被塞进了序列化的第一个字节里:

前缀字节总长度含义
0x0233 字节(66 位 hex)压缩编码;真实 Y 是偶数
0x0333 字节(66 位 hex)压缩编码;真实 Y 是奇数
0x0465 字节(130 位 hex)非压缩:04 ‖ X ‖ Y,两个坐标都显式存储
0x06/0x0765 字节混合形式(历史遗留):X ‖ Y 外加一个必须与 Y 一致的冗余奇偶位

这个比特不是校验和,也不是版本号。它只回答一个问题:「这个 X 对应的两个可能点里,我要的是哪一个?」

2. 解压缩究竟怎么算

给定 X,曲线方程就变成一个单未知数的方程:

Y² = X³ + 7  (mod p)   →   两个根:Y 与 p − Y

域上的二次方程最多两个解;若其中一个是 Y,另一个必然是 p − Y,因为在模 p 意义下 (p − Y)² = Y²。这两个根的奇偶性必然相反:p 是奇数,所以 p − Y ≡ −Y (mod 2) 会翻转最低位。一个偶根、一个奇根 —— 这就是一个比特 够用的原因。

还要注意,随机 X 大约一半的时候根本没有平方根:域元素里只有约一半是二次剩余,所以以 02 或 03 开头的 33 字节字符串里,约有一半压根不是合法的公钥。

求根通常用试探法(Tonelli–Shanks),但 secp256k1 的素数形状很特殊,存在闭式解。因为

p ≡ 3 (mod 4)   ⇒   √a = a(p+1)/4 mod p

对任何二次剩余 a 成立。理由很短:若 y = a(p+1)/4,则 y² = a(p+1)/2 = a · a(p−1)/2,而欧拉判别法告诉我们:只要 a 是二次剩余,就有 a(p−1)/2 ≡ 1。于是可以直接做一次以固定指数 为幂的模幂运算

(p + 1) / 4 = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFF0C

然后如果结果的奇偶性不对,就把它替换成 p − Y。在 secp256k1 上 p mod 4 = 3 精确成立,所以这条捷径永远可用;而 p ≡ 1 (mod 4) 的曲线就得用 更慢的通用算法。

解压缩没有产生任何新信息

很容易误以为 33 字节形式「丢掉」了什么。并没有:这个编码与「该 X 下的全部合法公钥」之间是双射。 这里也没有从私钥里恢复出任何东西 —— 信息从来不曾被移除,只是由曲线方程重新算了出来。 02 ‖ X 与非压缩的 04 ‖ X ‖ Y 描述的是同一个点。

3. 为什么必须拒绝曲线外的点

曲线方程是一道检验,不是一条提示:(X, Y) 要么满足 Y² = X³ + 7 (mod p), 要么不满足,不存在「差不多在曲线上」的状态。校验一旦失败,你手里拿的就不是公钥 —— 它不是群里的元素,用它做标量乘没有定义,其上任何协议都只是在吞垃圾。

这件事之所以要紧,是因为存在一整个被称为无效曲线攻击(invalid curve attack)的 攻击家族。假设某个协议会拿对方提供的点去乘一个秘密标量(ECDH 就是这么做的)。如果这个点没有被验证, 攻击者就可以发来落在另一条曲线上的点,或者落在一个小阶子群里的点。乘法的结果于是只依赖秘密的 少数几个比特。攻击者用许多这样的点做试验,再用中国剩余定理把零碎的答案拼起来,就能还原出完整的私钥。 已经有好几个 TLS 实现和智能卡实现正是这样被攻破的;而防御只有一行代码 —— 使用任何外部提供的点之前先验证 它。

需要诚实地补充一句:secp256k1 的余因子是 1、阶是素数 n。它没有小阶 子群,二次扭的阶也不光滑,所以在这条曲线上,教科书版本的小子群攻击无从下手。仅仅因为有人解析 过一个坏点,比特币并不会因此丢失。但这份纪律仍然不是可选项,有三个务实理由:

因此本页会解析点、校验方程,失败就拒绝继续。用 02 后跟 64 个 0 作为测试输入非常合适: 它会以一条可读的错误消息被拒绝,而不是默默从一个毫无意义的数字推导出一堆地址。

一个被接受的细节:X 会被对 p 取模

规范的 SEC1 编码要求 0 < X < p。严格的解码器 —— 包括比特币共识所依赖的 libsecp256k1 —— 会把大于等于 p 的 X 当作非规范编码而拒绝。本教学实现则 把 X 对 p 取模后继续,所以这里会有少数数值上古怪的输入被接受,而共识解析器 会拒绝它们。这是刻意的简化,也正是逐字节比较两个实现时会出现的那种差异。

4. 推导地址不需要私钥 —— 以及它的后果

从这里往下全是公开算术:把序列化公钥做哈希,再把哈希编码。这条流水线里没有任何一步需要标量 k,也没有任何一步可以反推出 k。

5. 压缩与非压缩

两种形式都是同一个点的合法编码,也都为共识所接受,但它们仍然会产出不同的地址 —— 因为地址 是序列化字节的哈希,而两者的序列化字节不同。

压缩非压缩
序列化02/03 ‖ X04 ‖ X ‖ Y
长度33 字节65 字节
演示私钥的 hash16021f57b6debcfc5b67182dfb4af1641f0a81890123f0e966dc089c611a9c1d03bd4f69ea53b0223f9
演示私钥的 P2PKH 地址146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT16kR3eiswUY6tmGnxZhwQmW6LAvTLGWG2G
花费时的 scriptSig约 107 字节(压栈 + 约 72 字节签名 + 33 字节公钥)约 139 字节(同样结构,公钥为 65 字节)
能否用于 P2WPKH/P2SH-P2WPKH/P2TR可以 —— 而且这是唯一允许的形式不能;witness 程序只定义在压缩公钥上
今日地位所有地方的默认选择(2012 年起)历史遗留,但依然有效、可花

由于非压缩公钥多出 32 字节、又直接嵌入输入脚本,从非压缩地址花费的手续费更高。这就是压缩形式最终 胜出的全部原因。

6. 实例演算 —— 真实的演示公钥

下面每一个值都是本页对输入框里的示例(02ff812e…67ee80)实际算出的结果:

步骤值
输入,66 位十六进制02ff812e26116a9aa140abe629e7f8a38401653caf925119def59ed3758c67ee80
前缀字节02 → Y 是偶数
X(前缀之后的 64 位)ff812e26116a9aa140abe629e7f8a38401653caf925119def59ed3758c67ee80
X³ + 7 mod p(要开平方的那个值)174ca53008928cd3c9c380e12c4b1dee0c5a0b6d851b1c472a58d744ca28c6dc
还原出的 Y —— 偶根8f49cde13c7ffd64f1d730bf87a743a578eda4971ddac4a08118160732b424ae
Y 的最后一位十六进制e → 偶数,与 02 前缀一致
另一个根 p − Y70b6321ec380029b0e28cf407858bc5a87125b68e2253b5f7ee7e9f7cd4bd781
p − Y 的最后一位十六进制1 → 奇数,与孪生根的预期相符
曲线方程校验通过 —— Y² 等于 X³ + 7 mod p
hash160(压缩)21f57b6debcfc5b67182dfb4af1641f0a8189012
P2PKH(压缩)146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT
P2SH-P2WPKH3DZT76KyKyc5zkzvLugP8umgt4RPY4XPQw
P2WPKHbc1qy86hkm0telzmvuvzm76279jp7z5p3yqjnaerk6
P2TRbc1pmsrhxnvmj8tjxxu9wj69ntvwvhvr28qufyc26tshz3rjj777tx3sh54u63

同一个点的非压缩对应物是那个 130 字符的字符串 04ff812e…b424ae,它产出的是完全不同的 地址 16kR3eiswUY6tmGnxZhwQmW6LAvTLGWG2G。

最后把前缀比特翻过来:同样的 X,声明为 03。本页于是还原出奇根 70b6321e…cd4bd781,即原点的负元。它的 hash160 是 bf2aa927b06822b645d48e54ac82676c2e586675,P2PKH 地址是 1JRoAmA3S9nPbucndLyARsmY2Awuzgdazb。如果 P = k·G,这个孪生点就是 (n − k)·G —— 编码里改一个比特,就是另一把私钥。

7. 链条上接下来发生什么

压缩公钥→ SHA-256→ RIPEMD-160→ hash160(20 字节)→ Base58Check / Bech32 / Bech32m→ 地址

8. 安全须知

9. 常见错误

10. 速查表

项目值
输入66 位十六进制:02 或 03 后跟 32 字节的 X
前缀含义02 = Y 为偶,03 = Y 为奇
域素数 p0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
p mod 43 —— 因此可以使用闭式平方根
开方指数 (p+1)/40x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFF0C
两个根Y 与 p − Y,奇偶性必然相反
曲线方程校验Y² ≡ X³ + 7 (mod p)
输出X、Y、奇偶性、hash160、P2PKH(压缩与非压缩)、P2SH-P2WPKH、P2WPKH、P2TR
需要私钥吗不需要 —— 以上没有一步能反推 k