非压缩公钥 → hash160 → 地址
解析 65 字节的 04‖X‖Y 公钥,验证它确实落在 secp256k1 上,做哈希并构建传统 P2PKH 地址 —— 再把同一个点的压缩序列化形式摆在一旁对比,它对应的是完全不同的地址。
请在上方输入内容后点击「转换」。不知道填什么?点「填入示例」即可载入占位符里的演示数据。
本页计算了什么
输入一个 65 字节的非压缩公钥 —— 以 04 开头的 130 位十六进制。输出:解析出的坐标、一次真实的
曲线方程校验、hash160、传统的 P2PKH 地址,以及并排对比的同一个点的压缩序列化形式,和它所产生的另一个
地址。
以及对照路径 —— 它只改变了第一个字节和整体长度:
1. 04 ‖ X ‖ Y 的布局
公钥不是一个可以查表的数字,它是 secp256k1 曲线上的一个点,而 SEC1 标准规定了怎么把一个点写下来。 长的写法是:一个字节的标志位,后面把两个坐标按大端序完整写出。
| 字段 | 字节 | 十六进制位 | 内容 |
|---|---|---|---|
| 前缀 | 0 | 0–1 | 04 —— 「后面是一个非压缩点」 |
| X | 1–32 | 2–65 | x 坐标,32 字节,大端序 |
| Y | 33–64 | 66–129 | y 坐标,32 字节,大端序 |
| 合计 | 65 | 130 | 共 520 位的序列化点 |
大端序意味着最高有效字节在最前面:序列化中出现的前导零字节是有意义的,绝不能删掉。X 以
00a3… 开头的公钥,与 X 以 a3… 开头的是两个不同的点;一个会顺手裁剪前导零的解析器,
迟早会把钱送到不存在的地方。
SEC1 里的每个前缀字节都是对后续内容的承诺,而它的种类比多数人以为的要多:
| 前缀 | 长度 | 含义 | 状态 |
|---|---|---|---|
02 | 33 字节 | 压缩:只有 x,y 为偶数 | 标准 |
03 | 33 字节 | 压缩:只有 x,y 为奇数 | 标准 |
04 | 65 字节 | 非压缩:x 与 y 都写出 | 标准,历史遗留 |
06 | 65 字节 | 混合:x 与 y 都写出,且 y 为偶数 | 已废弃 |
07 | 65 字节 | 混合:x 与 y 都写出,且 y 为奇数 | 已废弃 |
| (无) | 32 字节 | x-only,默认 y 为偶数(BIP340) | 仅用于 Taproot / Schnorr |
2. 这个点真的在曲线上吗
只有当坐标满足曲线方程时,这串字节才是一个「点」。secp256k1 定义在模素数 p 的域上,所以这个
检验就是一次模运算比较:
两边相等,点就在曲线上,后续流程才可以继续。如果不相等,这份输入根本不是公钥,之后的所有计算都毫无意义: 对它做哈希会得到一个看起来很正常、却永远没人能花掉的地址,因为根本不存在与它对应的私钥。
本页会做这项校验,并对曲线外的输入直接给出可读的错误,而不是照样渲染结果。这不是礼貌问题,而是安全边界:
如果程序不校验曲线方程就接受一个点,攻击者就可以提供一个位于另一条曲线上的点,而那条曲线的群阶要小 得多。用受害者的私钥标量去乘这个点,结果只会泄漏「私钥对该小阶取模」的信息 —— 但重复几次、换几个不同的 小阶,再用中国剩余定理,就能把完整的私钥拼回来。经典受害者是那些直接把对方送来的公钥用于 ECDH 的密钥 协商实现。对 secp256k1 来说余因子是 1,所以曲线内部没有小子群;真正的危险来自完全属于另一条曲线的 点。收下 65 字节、然后相信它的前缀,正是本页要避免的错误:先解析前缀,再验证方程,只有这两步都通过, 才会去哈希这个公钥。
3. 压缩与非压缩,是同一个点的两种写法
压缩不是有损的,也不是什么取巧手段。给定 X,方程
恰好有两个解:Y 与 p − Y。因为 p 是奇数,p − Y ≡ −Y
会翻转最低位,所以这两个根奇偶性必然相反:一个为偶,一个为奇。于是「y 是奇数还是偶数」这
一个比特就足以唯一确定这个点,而 02/03 前缀存的就是这个比特。反方向则是实打实的
计算,但很便宜:由于 p ≡ 3 (mod 4),平方根有闭式解
Y = (X³ + 7)(p+1)/4 mod p,之后按需要的奇偶性决定是否取负即可。
所以两个方向的转换都是无损的。真正容易出错的是它的后果:这两种序列化是不同的字节串, 哈希出不同的值,因此同一个私钥会对应不同的地址。
| 非压缩 | 压缩 | |
|---|---|---|
| 长度 | 65 字节 / 130 位十六进制 | 33 字节 / 66 位十六进制 |
| 前缀 | 04 | 按 y 的奇偶性取 02 或 03 |
| 携带的信息 | 完整的 X 与 Y | X 加一个奇偶性比特 |
| hash160(演示公钥) | 3f0e966dc089c611a9c1d03bd4f69ea53b0223f9 | 21f57b6debcfc5b67182dfb4af1641f0a8189012 |
| P2PKH 地址(演示公钥) | 16kR3eiswUY6tmGnxZhwQmW6LAvTLGWG2G | 146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT |
| 花费时推送的字节数 | 139(单输入、72 字节签名) | 107(同样的假设) |
| 能用于 SegWit v0 花费吗 | 不能 —— BIP143 要求压缩公钥 | 可以 |
| 引入时间 | 2009 年最初的客户端 | Bitcoin 0.6,2012 年 |
4. 混合型 06/07 前缀
「混合型」公钥长度是 65 字节 —— X 与 Y 都在 —— 但它的前缀声称自己知道 Y 的奇偶性:06 表示偶,
07 表示奇。换句话说,同一条信息被携带了两次。比特币核心从未产生过这种形式;它能存活下来,是因为
一些早期库接受它,而「被部分实现接受」正是一种传输格式最糟糕的状态。随之而来的是两类故障:
- 歧义。 生产者可以写一个与它所发送的 Y 相矛盾的前缀(比如
07配一个偶数的 Y)。 严格的解析器会拒绝它,宽松的解析器会忽略前缀,于是两派对同一串字节给出不同判断 —— 这是库层面的 「共识分裂」。 - 毫无收益。 混合形式没有省下任何东西:它和
04一样是 65 字节。
混合型公钥已被从建议标准中移除,现代钱包也都不再生成它。本页背后的库确实能识别 65 字节的 04、
06 与 07 输入,并对三者都做曲线方程校验 —— 但它不会把混合前缀与 Y 的奇偶性
交叉核对,所以一个 07 前缀配偶数 Y 的公钥也会被当作合法点接受。这种宽松处理正是该形式危险的原因:
同一串字节在不同库里会得到不同判断。因此本页直接拒绝 06/07,并要求你先把那一个字节
改成 04 再继续。改完之后,务必确认你得到的地址就是真正存放币的那个地址。
本页要求规范形式 04,如果你粘贴的是压缩公钥或混合型公钥,它会明确告诉你。若你手上有一个来自
老工具的 06/07 公钥,先把它改成 04(只改一个字节)再交给任何工具,
然后务必确认它算出的地址与真正存放币的那个地址一致。
5. 实例演算 —— 真实的演示公钥
| 步骤 | 取值 |
|---|---|
| 输入(130 位十六进制) | 04ff812e26116a9aa140abe629e7f8a38401653caf925119def59ed3758c67ee808f49cde13c7ffd64f1d730bf87a743a578eda4971ddac4a08118160732b424ae |
| 前缀 | 04 → 非压缩,65 字节 |
| X | ff812e26116a9aa140abe629e7f8a38401653caf925119def59ed3758c67ee80 |
| Y | 8f49cde13c7ffd64f1d730bf87a743a578eda4971ddac4a08118160732b424ae |
| Y 的奇偶性 | 末位十六进制是 e → 偶数 → 压缩前缀 02,混合前缀 06 |
Y² mod p | 174ca53008928cd3c9c380e12c4b1dee0c5a0b6d851b1c472a58d744ca28c6dc |
X³ + 7 mod p | 174ca53008928cd3c9c380e12c4b1dee0c5a0b6d851b1c472a58d744ca28c6dc —— 完全相同,点在曲线上 |
| 对 65 字节公钥做 hash160 | 3f0e966dc089c611a9c1d03bd4f69ea53b0223f9 |
| P2PKH 地址(非压缩) | 16kR3eiswUY6tmGnxZhwQmW6LAvTLGWG2G |
| 压缩序列化 | 02ff812e26116a9aa140abe629e7f8a38401653caf925119def59ed3758c67ee80 |
| 对 33 字节公钥做 hash160 | 21f57b6debcfc5b67182dfb4af1641f0a8189012 |
| P2PKH 地址(压缩) | 146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT |
| P2SH-P2WPKH(只能用压缩) | 3DZT76KyKyc5zkzvLugP8umgt4RPY4XPQw |
| P2WPKH(只能用压缩) | bc1qy86hkm0telzmvuvzm76279jp7z5p3yqjnaerk6 |
| x-only 32 字节形式(仅为参考地哈希一下) | 4d75c804c152bcc1e66a56cd6899f442b63dbf6c → 184a8MvQDPfePQPiVw3DUnAusPPvJmLGj7(这不是可花费的地址形式) |
一个点、一个私钥,却对应六个不同的目标字符串。请留意最后一行:在同时处理 Taproot 公钥的代码里,顺手把 x-only 形式拿去哈希是很常见的事故,而它产生的是一个任何钱包都不会去看的地址。
6. 只读钱包:一个公钥能替你做到什么
本页除签名以外的所有内容,都只靠公钥就能算出来。这正是只读钱包(watch-only wallet)的 基础:把公钥(更常见的是 BIP32 扩展公钥)交给一台服务器或手机,它就能推导出你将来会用的每一个地址、跟踪每一笔 收款、算出你的余额 —— 而始终不持有任何可以花钱的秘密。
这很有用,但也必须看清楚它的另一面:
- 它能看到一切。 公钥一旦泄漏,谁拿到它,谁就能读到这个公钥对应的完整历史与余额。钱动不了, 但「动不了」并不等于隐私。
- 这本来就是常规设计。 硬件钱包、闪电网络节点、商户对账、区块浏览器,全都依赖这种不对称性。 公钥不是可以随手乱丢的垃圾,它是一个会把你所有付款串联起来的标识符。
- 它不是花费能力。 要签名就需要
k。你校验别人给你的公钥是否在曲线上,检验的是 「它是不是一个真实的点」,而不是「你能不能动用它」。
7. 它在推导链中的位置
- 上游:私钥 → 非压缩公钥 产出的就是这 130 位字符串。
- 同辈:压缩公钥 → hash160 → 地址 对 33 字节形式做同一件事。
- 下游:hash160,然后是非压缩的 P2PKH 地址;如果想先用压缩形式,则走 P2WPKH。
8. 安全须知
- 别人给你的公钥,一定要先验证曲线方程再用。拒绝无效点是安全控制,不是形式主义。
- 还要确认
X < p与Y < p;坐标一旦落到域外就根本不是点,而有些库要等到 算术悄悄绕回来才发现这件事。 - 任何新东西都优先用压缩形式:更短、花费更便宜,而且 SegWit 强制要求。非压缩形式存在的意义,是找回 2012 年 以前打到它上面的币。
- 绝不要用非压缩公钥去推导 SegWit 程序。用 hash160(65 字节公钥) 算出的
bc1q…地址看起来完全 正常,却因为 BIP143 的压缩公钥要求而无法花费。
9. 常见错误
- 以为两种序列化对应同一个地址。 它们对应两个,而币只会在其中一个上。
- 哈希了错误的字节。 hash160 作用于序列化后的公钥,前缀也算在内。只哈希 X,或者 哈希 x-only 形式,都会得到第三个、毫无用处的地址。
- 裁剪前导零。 坐标是定长大端序的。把字符串截短就是在改点。
- 只看长度就相信它。 130 位十六进制并不能证明这个点存在;证明它存在的是曲线方程校验。
- 一个公钥收很多笔款。 这当然能行,代价是这些付款在链上被永久地关联在一起。
10. 速查表
| 项目 | 取值 |
|---|---|
| 布局 | 04 ‖ X ‖ Y,65 字节,130 位十六进制 |
| 曲线校验 | Y² ≡ X³ + 7 (mod p) |
| 域素数 | 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F |
| 压缩 | 丢掉 Y,把奇偶性放进前缀:02 为偶,03 为奇 |
| 解压缩 | Y = (X³+7)(p+1)/4 mod p,再按奇偶性修正 |
| 由它得到的地址 | Base58Check(0x00 ‖ hash160(65 字节公钥)) |
| 混合前缀 | 06/07 —— 已废弃,不要使用 |
| 兼容 SegWit 吗 | 不兼容;witness v0 要求压缩公钥 |