私钥 → P2PKH 压缩地址
经典的 1… 地址:把 33 字节压缩公钥哈希成 20 字节,前面加主网版本字节 0x00,后面加 4 字节双 SHA256 校验和,再做 Base58 编码。本页会把每个中间值都显示出来,让你逐字节看清构造过程。
请在上方输入内容后点击「转换」。不知道填什么?点「填入示例」即可载入占位符里的演示数据。
本页计算了什么
输入一个 256 位私钥,输出一个经典的 1… 地址。地址并不是第二把密钥,也不是私钥的哈希 —— 它是
对压缩公钥的 20 字节承诺值做 Base58Check 编码的结果:
结果面板会把每一个中间值都列出来,因为本页存在的意义就是让每一步都看得见,而不是藏在黑盒里。
1. 「P2PKH」到底是什么意思
比特币的一笔输出不是一个带余额的账户,而是一个金额加一小段程序,这段程序叫锁定脚本
(scriptPubKey)。要花掉它,下一笔交易必须提供一个解锁脚本(或 witness),让这段
程序执行完在栈上留下一个 TRUE。P2PKH 是 pay to public key hash
(支付给公钥哈希)的缩写,它的锁定脚本是:
OP_DUP OP_HASH160 <20 字节公钥哈希> OP_EQUALVERIFY OP_CHECKSIG
顺序很关键:脚本先对花费者提供的公钥重新求哈希,与脚本里承诺的哈希比对,只有比对通过才去验证签名。 「先哈希」正是地址能够这么短、并且公钥在币移动之前不必上链的原因。
那种 Unix 风格的简写 <公钥哈希> OP_CHECKSIG 描述的是更早的 P2PK
(pay to public key,直接支付给公钥)形式:它的锁定脚本里压入的是整把公钥,而不是公钥的哈希。中本聪最早的交易
用的就是它,代价是输出更大:
| P2PK(2009 年遗留形式) | P2PKH(本页) | |
|---|---|---|
| 锁定脚本 | <公钥> OP_CHECKSIG | OP_DUP OP_HASH160 <hash160> OP_EQUALVERIFY OP_CHECKSIG |
| scriptPubKey 大小 | 35 字节(压缩)/67 字节(非压缩) | 25 字节 |
| 花费前公钥是否已在链上 | 是 —— 从第一天就公开 | 否 —— 只有花费时才暴露 |
| 今天的使用情况 | 罕见,主要是 2009–2010 年从未动过的币 | 此后十年单密钥钱包的默认格式 |
脚本执行的每一步
花费者的解锁脚本是 <签名> <公钥>。下面用演示私钥的真实取值,逐步展示解释器的动作:
| # | 操作 | 执行后的栈 |
|---|---|---|
| 1 | 从 scriptSig 压入签名 | [sig] |
| 2 | 从 scriptSig 压入压缩公钥 | [sig, 02ff812e…ee80] |
| 3 | OP_DUP —— 复制栈顶 | [sig, 公钥, 公钥] |
| 4 | OP_HASH160 —— 对副本求哈希 | [sig, 公钥, 21f57b6d…9012] |
| 5 | 压入脚本中承诺的哈希 | [sig, 公钥, 21f57b6d…9012, 21f57b6d…9012] |
| 6 | OP_EQUALVERIFY —— 比较、弹出两者,不等则立即失败 | [sig, 公钥] |
| 7 | OP_CHECKSIG —— 用公钥验证签名 | [TRUE] |
可见哈希不是「顺手做的优化」,它就是身份校验本身。若花费者给出的公钥哈希不匹配,
OP_EQUALVERIFY 会直接失败,根本轮不到签名运算。
2. 逐字节看构造过程
Base58Check 的输入恰好是 25 字节,此外什么都没有 —— 没有 chain code、没有密钥序号、更没有私钥的什么 校验值:
| 偏移 | 长度 | 字段 | 演示取值 |
|---|---|---|---|
| 0 | 1 字节 | 版本字节 0x00 = 主网 P2PKH | 00 |
| 1 – 20 | 20 字节 | hash160 = RIPEMD160(SHA256(压缩公钥)) | 21f57b6debcfc5b67182dfb4af1641f0a8189012 |
| 21 – 24 | 4 字节 | 校验和 = SHA256(SHA256(第 0–20 字节)) 的前 4 字节 | cbd7667e |
| — | 共 25 字节 | 200 位,这就是一个 1… 地址的全部内容 | 0021f57b…9012cbd7667e |
25 字节 = 200 位。由于 Base58 每个字符携带 log₂(58) ≈ 5.858 位信息,编码后的长度是 33 或 34 个字符 (200 / 5.858 ≈ 34.1)。演示地址正好 34 个字符。
为什么地址一定以「1」开头
Base58 本质上是「以 58 为进制的整数转换」,而纯粹的整数转换会把前导零字节抹掉。于是编码规则里额外加了
一条:输入中每一个前导的 0x00 字节,在输出开头对应一个字面字符
1。主网 P2PKH 的版本字节正好就是 0x00,所以第一个字符永远是
1。改掉版本字节,首字符随之改变 —— 这一个字节就是 1…、3…、
m… 长得不一样的全部原因。
合法的主网 P2PKH 地址必定以 1 开头,但反过来不成立:解码器必须同时检查版本字节、载荷长度
以及校验和。永远不要把前缀当作校验 —— 下面那个演示测试网地址之所以以 m 开头,正是
这个道理。
3. 为什么是 hash160 = RIPEMD160(SHA256(x))
两个不同的哈希函数串联使用,理由是纵深防御。仅攻破 SHA-256 的碰撞性对攻击者
毫无用处,因为 32 字节摘要还要喂给第二个结构完全不同的函数:想造出两把 hash160 相同的公钥,
必须在复合函数上找到碰撞,也就是两个设计都得破。同时,哈希两次也把结果压缩到 20 字节,让每个地址、
脚本和输出都更小。
| 函数 | 输出 | 生日碰撞界 | 原像界 | 在本页中的作用 |
|---|---|---|---|---|
| SHA-256 | 32 字节 / 256 位 | 约 2128 | 约 2256 | 对公钥做全强度承诺 |
| RIPEMD-160 | 20 字节 / 160 位 | 约 280 | 约 2160 | 把承诺值变短 |
| hash160 = RIPEMD160∘SHA256 | 20 字节 / 160 位 | 约 280 | 约 2160 | 地址承诺的就是它 |
针对某个具体地址的现实威胁是「第二原像」,而不是随便找一个碰撞:攻击者必须找到一把公钥,它的 哈希等于你那 160 位的值,代价约 2160。280 的碰撞界只影响攻击者自己挑选的两把 密钥,因此用 20 字节换取更小的脚本被认为是划算的取舍 —— 而且直到今天它依然没有被攻破。
4. 那 4 个字节的校验和究竟防住了什么
校验和是 SHA256(SHA256(payload))[0..3],即 32 位,编码前附在载荷后面。它的全部职责是捕获
无意的抄写错误:抄错一个字符后解码出的整数就变了,而随机损坏仍然能碰巧匹配这 32 位的概率是
2-32 ≈ 1 / 42.9 亿。这就是为什么地址少抄一个字符时,几乎所有钱包都会大声报错。
校验和没有密钥、算法公开:任何人都能为自己想要的载荷算出一个正确的校验和 —— 包括一个把钱付给 他自己的载荷。它防的是笔误和截断,防不了在邮件、剪贴板或被人动手脚的网页里被替换掉的地址。 请在持有私钥的设备上核对地址的头尾若干字符。
5. 主网 vs 测试网:一个字节决定一切
对同一个 hash160,主网地址与测试网地址的唯一区别就是版本字节。同样的 20 字节,不同的首字节,完全不同的 字符串:
| 网络 | P2PKH 版本 | P2PKH 前缀 | P2SH 版本 | P2SH 前缀 | WIF 版本 | Bech32 前缀 |
|---|---|---|---|---|---|---|
| 主网 | 0x00 | 1… | 0x05 | 3… | 0x80 | bc1 |
| 测试网 / signet / regtest* | 0x6F | m… / n… | 0xC4 | 2… | 0xEF | tb1 |
* 这几个测试网络共用上表里的 Base58 版本字节,只有 bech32 的可读部分不同(regtest 为
bcrt1)。对演示私钥的 hash160,主网地址是
146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT,测试网地址是
micWfnN6LUy38jVRPD2Mw7YMa873zjixGw —— 同一个 20 字节承诺,指向两条不同的链。
两个字符串解码出的 hash160 相同,但版本字节是收款链上输出脚本的一部分。把主网的币付给一个
tb1… 或 m… 地址,等于在一条链上向「你在另一条链上掌握私钥」的地址转账 ——
在主网上这些币直接丢失。这类复制粘贴错误不可撤销,没有任何客服可以找。
6. 用演示私钥做的实例演算
下面就是本页对 0824c314…171ca 实际算出的全部值,结果面板会实时重算它们:
| 步骤 | 取值 |
|---|---|
| 私钥 k | 0824c314772b2c2859c889471390a36bf66e53a1ca1642f96f0f2c9307a171ca |
| 压缩公钥(33 字节) | 02ff812e26116a9aa140abe629e7f8a38401653caf925119def59ed3758c67ee80 |
| 它的 SHA-256(32 字节) | 067eb00a0b9864633b020eef374476142daba913c5481ad6a4741cc8ab702617 |
| hash160 = 其 RIPEMD-160(20 字节) | 21f57b6debcfc5b67182dfb4af1641f0a8189012 |
载荷 = 00 ‖ hash160(21 字节) | 0021f57b6debcfc5b67182dfb4af1641f0a8189012 |
| 校验和(4 字节) | cbd7667e |
| 被编码的 25 字节 | 0021f57b6debcfc5b67182dfb4af1641f0a8189012cbd7667e |
| P2PKH 地址 | 146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT(34 字符) |
| 对应的 scriptPubKey(25 字节) | 76a91421f57b6debcfc5b67182dfb4af1641f0a818901288ac |
读这段脚本:76 = OP_DUP,a9 = OP_HASH160,
14 = 「接下来压入 20 字节」,随后是哈希本身,88 = OP_EQUALVERIFY,
ac = OP_CHECKSIG。五个操作码加一个常量 —— 25 个字节定义了谁有权花这笔钱。
7. 为什么地址不是公钥
- 它是单向承诺。 地址里并不存公钥,只存它的 160 位哈希。想从地址还原公钥,等于要逆转 SHA-256 与 RIPEMD-160,目前除暴力搜索外没有更好的办法。
- 只有地址无法验证签名。 ECDSA 验证必须拿到公钥,这就是花费者必须在解锁脚本里交出公钥的 原因。
- 地址不告诉你公钥是怎么序列化的。 压缩公钥和非压缩公钥生成的
1…地址看起来 一模一样:版本字节相同、长度相同。你无法从地址判断币到底躺在压缩还是非压缩的那个变体上。 - 它当然也不是私钥。 公开地址不会泄漏任何足以花费的信息 —— 这正是它可以随手给人的原因。
因为公钥在币移动之前一直隐藏,一个从未花费过的 P2PKH 地址同时受到两个独立难题的保护:哈希原像
(2160),以及后来看到公钥的人面临的那道椭圆曲线离散对数题。已经花费过的地址则把
公钥永久暴露,第一层保护随之消失 —— 在考虑未来的量子攻击者时,这是个必须纳入考量的区别。
8. 地址复用是隐私问题,不是共识问题
区块链是公开且永久保存的账本,所以地址不是一个能躲在其后的账户,而是一个永久标签。向同一地址的每一笔 付款,连同金额与时间,都会被任何人关联起来。有两个后果值得强调:
- 聚类分析。 把同一个地址用于发工资、交易所提现和捐款,观察者无需破解任何密码学,就能 画出你的收入、对手方与消费图谱。
- 密钥暴露。 一个地址第一次花费时,那笔输出的公钥就永久公开了。而使用新地址可以为所有 尚未移动的资金保留「原像」这一层保护。
标准解法是分层确定性钱包(BIP32/BIP44):从同一个种子为每一笔收款派生新地址,找零也发往新地址。 复用地址既不多花手续费,在链上也完全合法 —— 这正是大量软件依然这么干的原因。
9. 这一步在推导链上的位置
- 上游:私钥 → 压缩公钥 提供这里要哈希的那 33 字节。
- 同辈:用非压缩 65 字节公钥构建的同类型地址 —— 同一个秘密,另一个地址。
- 同辈:嵌套 SegWit 的
3…地址 与 原生 SegWit 的bc1q…地址,它们复用完全相同的hash160。 - 反方向:公钥 → hash160 → 各类地址,完全不需要私钥。
10. 安全须知
本工具的一切计算都在提供它的服务器的 PHP 里完成,不写日志、不外发 —— 但这条保证的上限就是运营者本身。 任何在日志、代理、截图或浏览器历史里瞥见你私钥的人,都能花掉由它派生出的所有地址上的全部币。真要管钱, 请用你自己构建、离线运行的软件,或者硬件钱包。
- 地址不泄漏密钥信息,可以放心公开;私钥和 WIF 不行。
- 请在签名设备上逐字符核对地址。4 字节校验和只能抓住笔误,抓不住蓄意替换。
- 面对新地址,先小额试转,等确认后再转剩余部分。
11. 常见错误
- 不小心哈希了非压缩公钥。 把
K…/L…WIF 导入一个按 65 字节 形式求哈希的钱包(或反过来),余额会显示为零,而币其实安然躺在另一个地址上。 - 以为地址可以被反推。 无论多少算力,都不可能把
146ZNjH7…变回公钥或私钥; 那需要遍历哈希的全部原像,不现实。 - 把前缀当校验。 以
1开头既不证明地址正确,也不证明网络正确,甚至不证明 它是 P2PKH —— 去解码。 - 手工「修正」被拒绝的地址。 钱包提示「校验和无效」就意味着地址是错的;靠猜去补正是 销毁币的经典方式。
- 主网和测试网混用。 两者看起来都像那么回事,决定币落在哪条链上的是版本字节。
12. 速查表
| 项目 | 取值 |
|---|---|
| 公式 | Base58Check(0x00 ‖ hash160(压缩公钥)) |
| 哈希输入 | 33 字节压缩公钥(66 位十六进制) |
| 哈希函数 | hash160 = RIPEMD160(SHA256(x)),20 字节 |
| 版本字节 | 主网 0x00,测试网 0x6F |
| 被编码的载荷 | 25 字节 = 1 版本 + 20 哈希 + 4 校验和 |
| 校验和 | SHA256(SHA256(payload)) 的前 4 字节,32 位 |
| 地址长度 | 33 或 34 个 Base58 字符 |
| 锁定脚本大小 | 25 字节 |
| 演示地址 | 146ZNjH7XTXnMd1ofe3z7CL2i8WM7N2UqT |
| 可逆吗 | 不可逆 —— 单向哈希承诺 |