私钥 → 非压缩公钥
在 secp256k1 上计算 P = k·G,并把该点序列化成最初的 65 字节形式 04‖X‖Y —— 2012 年之前生成的每一把密钥都用这种编码,也只有它能复现老式非压缩地址与 5… 开头的 WIF。
请在上方输入内容后点击「转换」。不知道填什么?点「填入示例」即可载入占位符里的演示数据。
本页计算了什么
你输入一个 256 位的私钥 k,本页给出它的非压缩公钥:
把椭圆曲线上的点 P = k·G 完整写出来 —— 两个坐标一个不少,前面加一个 04 字节作为标记。
总共 65 字节,这正是中本聪最初的客户端为每一把密钥使用的格式。
这里没有任何新的密码学。曲线上的运算与「压缩公钥」那一页完全一样, 不同的只是把结果序列化的方式 —— 而正是这个差别,让同一把私钥拥有两个彼此无关的地址。
1. 为什么非压缩形式正好是 65 字节
公钥是 secp256k1 上的一个点:两个落在 [0, p−1] 区间、满足
Y² ≡ X³ + 7 (mod p) 的数 X 和 Y,其中
p = 0xFFFFFFFF…FFFFFC2F(256 位)。既然每个坐标都小于 p,那么每个坐标都能装进
32 字节。编码方式也就是最直白的那种 —— 先来一个字节声明「下面是一个非压缩形式的点」,
再跟上两个坐标:
| 偏移(字节) | 长度 | 字段 | 说明 |
|---|---|---|---|
| 0 | 1 | 类型标记 / 前缀 | 04 = 非压缩点 |
| 1 | 32 | X 坐标,大端序,左补零 | P = k·G 的第一个坐标 |
| 33 | 32 | Y 坐标,大端序,左补零 | P 的第二个坐标 |
| 合计 65 字节 | 520 位 → 130 位十六进制 | ||
有三个细节很容易出错:
- 坐标是定长的。 与 DER 编码的整数不同(后者会省掉前导零字节),SEC1 的坐标永远是
32 字节。假如
X恰好是0x00a1…,那个前导00字节必须保留。 删掉它会让后面每个字节都前移,得到一个长度不同的「公钥」—— 一些有缺陷的解析器当年就是这么干的。 - 大端序。 标记之后的第一字节就是
X的最高有效字节。密钥序列化从不 使用小端序,这与比特币里某些其它结构不同。 04不是数字的一部分。 它是标记,正如压缩形式的02/03也是标记。做哈希时要把 65 字节当作一个整体,标记同样参与哈希。
2. 前缀字节:04,以及被废弃的 06/07
第一个字节来自 SEC1 —— 定义椭圆曲线点如何写成字节串的那份标准。SEC1 给每种点编码 分配了一个字节的标识,比特币把这些标识全都继承了下来:
| 前缀 | 名称 | 结构 | 长度 | 今天的状况 |
|---|---|---|---|---|
00 | 无穷远点 | — | 1 字节 | 永远不能作为公钥;k = 0 才会得到它 |
02 | 压缩,Y 为偶 | 02 ‖ X | 33 字节 | 现代标准形式 |
03 | 压缩,Y 为奇 | 03 ‖ X | 33 字节 | 现代标准形式 |
04 | 非压缩 | 04 ‖ X ‖ Y | 65 字节 | 历史遗留,但在旧脚本里完全合法 |
06 | 混合,Y 为偶 | 06 ‖ X ‖ Y | 65 字节 | 已淘汰;奇偶位是冗余的 |
07 | 混合,Y 为奇 | 07 ‖ X ‖ Y | 65 字节 | 已淘汰;奇偶位是冗余的 |
| 无 | x-only(BIP340 / Taproot) | X | 32 字节 | 仅 Taproot 使用现代形式 |
混合(hybrid)形式 06 和 07 把 Y 的奇偶性
塞进标记的最低位(06 为偶、07 为奇),同时又老老实实把 Y 完整写了一遍。
于是那个奇偶位没有提供任何 Y 字节尚未提供的信息,反而给了攻击者第二个可篡改的冗余字段:
把标记一翻,就得到一个自相矛盾的密钥。SEC1 后来的修订版正是出于这个理由删掉了混合编码,也从没有哪个钱包
生成过它们,链上几乎没有实际使用量。本站的解析器仍然接受 06/07 开头的密钥,
是为了让你能亲眼看看它们长什么样 —— 但绝不要自己生成或保存这种密钥。
这里的 04 是点的标记。它与地址的版本字节(主网 P2PKH 是 0x00)、
以及 WIF 的版本字节(0x80)都不是一回事。同一条推导链上会出现三种不同的「前缀字节」,
把它们混为一谈是经典的入门错误。
3. 这个格式从哪来 —— 以及为什么 2012 年改了
2009 年的原始比特币客户端通过 OpenSSL 生成密钥,而 OpenSSL 对 EC 点的默认字节串编码就是非压缩的。
因此比特币头三年里所有软件创建的密钥都是 65 字节的 04‖X‖Y,早期区块链上的每个
地址都是这 65 字节的 hash160。这是历史默认值,不是谁手动打开的某个「遗留模式」。
压缩是后来作为节省空间的优化被提出来的。一个点的 Y 坐标完全由 X 加上一个比特
(奇偶性)决定,所以 65 字节里有 32 字节是冗余的。一份 BIP 式的提案把这次改动梳理清楚,
2012 年 3 月发布的 Bitcoin 0.6.0 正式支持压缩公钥,并把它作为新生成密钥的默认形式。
动机纯粹是经济与工程上的:
- 每次花费 P2PKH 输出,scriptSig 里都要塞进公钥。用 33 字节替代 65 字节,每个输入省下 32 字节 —— scriptSig 缩小约 23%,在规模上就是真金白银。
- 输入更小意味着 UTXO 集更小、区块链更小,这在 2012 年就已经是实实在在的担忧。
- 安全性完全一样:两种编码描述的是同一个点,而 ECDSA 根本不关心这个点当初是怎么写下来的。
由于这次改动改变的是被哈希的字节,钱包必须告诉用户某把密钥属于哪种形式 —— 而裸私钥本身不携带这个信息。
这正是 WIF 格式在同一次发布中增加 0x01 压缩标志的全部原因(见
私钥 → 压缩 WIF)。关键在于:这次改动是增加了一种格式,而不是让旧格式失效。
2012 年躺在非压缩地址上的币,今天依然可以在同样的共识规则下花掉。
4. 为什么非压缩形式今天仍然重要
- 旧资金。 2012 年年中之前生成的任何密钥或地址,以及此后由从未采用压缩的软件创建的
密钥,其币都躺在
hash160(04‖X‖Y)上。要找回这些币,就必须精确复现那 65 字节的字符串。 - 纸钱包。 2011—2013 年印出来的纸钱包,以及同一时期许多实物比特币收藏品,都是用
非压缩密钥制作的。它们上面印的私钥是
5…开头的 WIF,正是因为这套搭配是 「非压缩公钥 + 非压缩地址」。 - 清扫(sweep)。 要从这种地址花钱,scriptSig 必须推入一把公钥,其 hash160 与地址里 承诺的值相等。如果你推入的是压缩公钥,P2PKH 校验就会失败 —— 交易会被拒绝,而不是被悄悄转到别处。
- 取证与恢复。 给定一个地址和一把候选私钥,你必须同时算出两种序列化,才能判断这个地址 属于哪一种 —— 本页做的正是这件事。
SegWit witness v0 的规则要求公钥必须是压缩的:P2WPKH 与 P2SH-P2WPKH 输出只能用 33 字节公钥花费。
现代那些基于 descriptor 的钱包也一样,很多在导入时就直接拒绝非压缩密钥。所以非压缩密钥只能通向
P2PKH(以及历史上的裸 P2PK)脚本 —— 你无法把它变成 bc1q… 地址。
5. 用真实演示数据演算一遍
下表全部是本页对输入框里那个示例私钥实际算出的值。点一下「填入示例」就能复现:
| 步骤 | 值 |
|---|---|
私钥 k(十六进制) | 0824c314772b2c2859c889471390a36bf66e53a1ca1642f96f0f2c9307a171ca |
| 私钥(十进制) | 3683455675284633286911943861444039993120875154046227415438637967083965608394 |
P = k·G 的 X | ff812e26116a9aa140abe629e7f8a38401653caf925119def59ed3758c67ee80 |
P 的 Y | 8f49cde13c7ffd64f1d730bf87a743a578eda4971ddac4a08118160732b424ae |
| Y 的奇偶性 | 末位十六进制是 e → 偶数(所以这把密钥的压缩兄弟以 02 开头) |
| 非压缩公钥(本页输出) | 04ff812e26116a9aa140abe629e7f8a38401653caf925119def59ed3758c67ee808f49cde13c7ffd64f1d730bf87a743a578eda4971ddac4a08118160732b424ae |
| 它的长度 | 65 字节 = 130 位十六进制 = 520 位 |
| 对这 65 字节做 hash160 | 3f0e966dc089c611a9c1d03bd4f69ea53b0223f9 |
| 由它得到的 P2PKH 地址 | 16kR3eiswUY6tmGnxZhwQmW6LAvTLGWG2G |
| 对照:压缩公钥 | 02ff812e26116a9aa140abe629e7f8a38401653caf925119def59ed3758c67ee80 |
| 对照:它的 hash160 | 21f57b6debcfc5b67182dfb4af1641f0a8189012 |
| 对照:它的 P2PKH 地址 | 146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT |
最后三行才是本页的重点。同一个 256 位数字 k 同时对应
16kR3eis…GWG2G 和 146ZNjH7…2UqT。它们不是别名:它们是两个不同的 20 字节承诺值、
两个不同的地址,而钱包通常只盯着其中一个。
地址本身是一个用上面的 hash160 构造出来的 Base58Check 结构:
| 地址组成部分 | 长度 | 演示值 |
|---|---|---|
| 版本字节 | 1 字节 | 00 |
| hash160 载荷 | 20 字节 | 3f0e966dc089c611a9c1d03bd4f69ea53b0223f9 |
| 校验和 = SHA256d(载荷) 的前 4 字节 | 4 字节 | 3b0b7cbd |
| 编码结果 | 34 个 Base58 字符 | 16kR3eiswUY6tmGnxZhwQmW6LAvTLGWG2G |
6. 压缩与非压缩对照表
| 非压缩 | 压缩 | |
|---|---|---|
| 序列化 | 04 ‖ X ‖ Y | 02/03 ‖ X |
| 字节 / hex 位数 / 比特 | 65 / 130 / 520 | 33 / 66 / 264 |
| 携带的信息 | 两个坐标 | X 加上 Y 的奇偶性 |
| hash160 的输入 | 全部 65 字节 | 全部 33 字节 |
| 同一把密钥的 P2PKH 地址 | 16kR3eis…GWG2G | 146ZNjH7…2UqT |
| 对应 WIF 前缀 | 5… | K…/L… |
| 花费时推入的公钥字节数 | 65 | 33 |
| 典型 P2PKH scriptSig 大小 | 1 + 72 + 1 + 65 = 139 字节 | 1 + 72 + 1 + 33 = 107 字节 |
| 能否用于 witness v0 / Taproot | 不能 | witness v0 可以(Taproot 用 x-only) |
| 从何时成为默认 | Bitcoin 0.1(2009) | Bitcoin 0.6.0(2012 年 3 月) |
| 今天是否仍然合法 | 是,在旧式脚本类型中 | 是 |
那个 scriptSig 的算式值得展开说明:花费 P2PKH 要推入一个 DER 签名加上 1 字节 sighash 类型(约 72 字节) 和一个公钥,每个前面还有一个长度字节。在按虚拟字节计费的手续费体系下,那 32 字节的差额会在每一个输入上、 永远地付出去。
7. 一把私钥、两个地址 —— 最经典的「我的币丢了」
数字 k 就只是一个数字。「压缩」还是「非压缩」是序列化的属性,而在钱包备份里,
记录这个选择的唯一地方就是 WIF 字符串中的一个标志字节。把一把非压缩私钥导入一个默认压缩的钱包,
它会推导 hash160(02/03‖X)、去查 146ZNjH7…、什么也找不到,然后显示余额为零 ——
而你的币其实安安稳稳地躺在 16kR3eis… 上。什么也没丢,但看起来和丢了没有区别,
而这就是这类故事里最常见的一种。
有三点值得记住:
- 两个地址都由你控制。 同一把私钥同时掌管压缩地址和非压缩地址。如果很久以前有人往旧地址 给你打过钱,那些币今天仍然可以动。
- 它们无法合并。 你没法把非压缩地址「转换」成压缩地址;只能发一笔普通交易,把币从前者 转到后者,并支付手续费。
- 下结论前先两种都查。 当恢复出来的钱包显示为零时,把两种形式都算出来(本页与 它的压缩孪生页做的正是这件事),再到链上分别搜索这两个地址。
8. 这一步之后会发生什么
- 私钥 → P2PKH 非压缩地址 —— 完整的地址构造过程,含版本字节与校验和。
- 私钥 → 非压缩 WIF —— 与之配套的
5…备份字符串,也就是你真正 会导入钱包的那个东西。 - 私钥 → 压缩公钥 —— 33 字节的那个兄弟,以及它自己的地址。
- 非压缩公钥 → hash160 → 地址 —— 从你已经持有的公钥出发做同样的计算,附带 曲线方程校验。
9. 安全须知
- 65 字节不会降低安全性。 压缩与非压缩是同一个曲线点;离散对数问题、签名方案与有效 密钥强度完全相同。「非压缩」意味着「更长」,不意味着「更弱」。
- 花费时更贵。 更大的 scriptSig 意味着更大的交易,在转移同样价值时要付更高的手续费。 这是唯一的实际代价,也正是现代钱包不再发放非压缩地址的原因。
- 收到的点必须校验。 曲线外的
(X, Y)组合可以用来对粗心的实现发起无效曲线 攻击。本站会在使用一个点之前验证Y² ≡ X³ + 7。 - 填进网页表单的私钥就是上了网的私钥。 本页通过请求行提交,而任何到达服务器的内容都可能 被日志或代理记录下来。请把本工具当成教学用具:只用一次性测试密钥做实验,真正的资金请放在你自己 掌控的软件里操作。
- 量子威胁不变。 被公开的公钥 —— 无论压缩与否 —— 才是 Shor 算法攻击的对象;多出来的 32 字节买不到任何抗量子能力。
10. 常见错误
- 丢掉
04。 这个标记是 hash160 输入的一部分。一个 64 字节的 「X‖Y」串会哈希出完全不同的东西,而且根本不是一个合法公钥。 - 把坐标的前导零字节去掉。 定长是硬性要求:每个坐标永远是 32 字节。
- 以为压缩与非压缩是两把不同的密钥。 它们是同一个点的两种序列化,由同一把私钥控制。
- 指望非压缩密钥能用在 SegWit 里。 witness v0 要求压缩,非压缩密钥在那里根本用不了。
- 以为
04标记编码了奇偶性。 并没有。只有混合形式的06/07和压缩形式的02/03才携带奇偶信息。 - 用压缩公钥去花非压缩地址上的 UTXO。 脚本会失败;钱包必须推入与地址哈希值完全对应的 那一把公钥。
11. 速查表
| 项目 | 值 |
|---|---|
| 公式 | secp256k1 上的 P = k·G |
| 编码 | 0x04 ‖ X(32) ‖ Y(32) |
| 长度 | 65 字节 / 130 位十六进制 / 520 位 |
| 前缀含义 | 02/03 压缩,04 非压缩,06/07 混合(已淘汰) |
| 坐标 | 大端序、定长 32 字节、对 p 取模 |
| 前缀在哪里起作用 | 在 hash160 的预映像里 —— 它会改变地址 |
| 可导出的地址类型 | 仅 P2PKH(1…)与历史上的裸 P2PK |
| 配套的备份格式 | 以 5 开头、51 个字符的 WIF |
能反推出 k 吗 | 不能(ECDLP) |
| 链上仍然有效吗 | 在旧式脚本类型中有效 |