- 示例工程
- 区块链
【免费下载链接】Dapp-Learning
Dapp learning project for developers at all stages. Becoming and cultivating sovereign individuals. Nonprofit organization.
P2PKH(Pay-to-Public-Key-Hash,支付到公钥哈希)是比特币最早也是最常见的交易输出类型,本指南围绕 BTC/Basic/payment/P2PKH.md 展开,深入剖析 P2PKH 的锁定/解锁脚本结构、脚本执行流程、地址生成全过程,并结合本仓库的 JavaScript 示例代码与配套文档进行源码级验证。读完本文,你将能够理解 P2PKH 交易从地址生成、脚本构造到签名广播的完整链路,并能动手运行仓库中的脚本亲手验证。
一、P2PKH 是什么
P2PKH 是比特币网络中最常用的一种交易类型,设计用来将比特币支付到某个具体的公钥哈希(Public Key Hash),而不是直接支付到公钥本身。这种方式提供了更高的安全性和隐私保护:比特币被发送到一个地址,这个地址实际上是持有者公钥的哈希版本。
P2PKH 地址通常以数字"1"开头。地址不仅简洁,而且通过哈希公钥,隐藏了公钥的实际内容,增加了隐私保护层——在花费资金之前,收款方的公钥不会暴露在区块链上,只有签名那一刻公钥才被揭示。
提示:P2PKH 属于比特币地址体系中的"传统"类别。在 支付方式总览 中可以看到,比特币地址家族还包括以 "3" 开头的 P2SH-P2PKH、以 "bc1q" 开头的 P2WPKH(隔离见证)以及以 "bc1p" 开头的 P2TR(Taproot),P2PKH 是理解所有这些格式的基础。
二、锁定脚本 ScriptPubKey
比特币的每一笔交易输出都包含一个锁定脚本(ScriptPubKey),它规定了"谁可以花费这笔钱"的条件。P2PKH 脚本模式包含一个公钥哈希,该哈希和以下操作码共同构成锁定脚本:
// 模版 OP_DUP OP_HASH160 <Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG OP_DUP // 复制栈顶的元素 OP_HASH160 // 弹出栈顶元素,计算其SHA-256散列,然后计算RIPEMD-160散列 OP_PUSHBYTES_20 // 推送20字节的公钥哈希到栈顶 18e1fad25b2983d5dbb2e2b96e3ce756a69b3bc2 // 公钥哈希 OP_EQUALVERIFY // 比较栈顶元素是否匹配 OP_CHECKSIG // 验证数字签名各操作码的职责:
- OP_DUP:复制栈顶元素(这里是花费者提供的公钥)。
- OP_HASH160:弹出栈顶元素,先计算其 SHA-256 散列,再计算 RIPEMD-160 散列,得到公钥哈希(即 HASH160 = RIPEMD160(SHA256(x)))。
- OP_PUSHBYTES_20:向栈中推送 20 字节的公钥哈希。
- OP_EQUALVERIFY:比较栈顶的两个元素是否相等,若不相等则整个脚本验证立即失败。
- OP_CHECKSIG:验证数字签名,是脚本的最终把关环节。
注意这里的公钥哈希是18e1fad25b2983d5dbb2e2b96e3ce756a69b3bc2,这是一个 20 字节(40 个十六进制字符)的 HASH160 值,它来源于签名教程中同一个公钥的哈希计算,与 签名文档 中的示例保持了一致性。
三、解锁脚本 ScriptSig
要解锁花费此脚本,上面公钥的所有者需要提供原始公钥以及有效的签名(由对应的私钥对交易内容签名生成):
// 模版 <Singature> <Public Key> OP_PUSHBYTES_72 // 推送72字节到栈顶 3045022100c233c3a8a510e03ad18b0a24694ef00c78101bfd5ac075b8c1037952ce26e91e02205aa5f8f88f29bb4ad5808ebc12abfd26bd791256f367b04c6d955f01f28a772401 // 签名数据 OP_PUSHBYTES_33 // 推送33字节到栈顶 03480b6822120e9936b43859d84c380583c3d0292409b21453ae962815090f8117 // 压缩公钥签名数据30450221...772401是一个DER 编码的 ECDSA 签名,末尾的01是签名哈希类型(SIGHASH_ALL,表示签名覆盖交易的所有输出),其结构可拆解如下(详见 签名文档 的"签名分析"一节):
| 字节 | 含义 |
|---|---|
30 | 序列(SEQUENCE)开始 |
45 | 整个签名结构的长度(69 字节) |
02 | 第一个整数(r 值)开始 |
21 | r 值长度(33 字节,含前导 0 表示正数) |
00c233...e91e | r 值 |
02 | 第二个整数(s 值)开始 |
20 | s 值长度(32 字节) |
5aa5f8...7724 | s 值 |
01 | SIGHASH 类型 |
公钥03480b6822...f8117是一个 33 字节的压缩公钥(以03开头表示 Y 坐标为奇数)。这里使用的是 ECDSA 签名算法——比特币早期的交易认证完全建立在 ECDSA 之上,其"私钥签名、公钥验签"的数学原理(基于 secp256k1 椭圆曲线)可以参阅 ECDSA 教程。
四、脚本执行过程
1. 脚本合并
验证时,节点将 ScriptSig 放在前面、ScriptPubKey 放在后面合并执行:
<Singature> <Public Key> OP_DUP OP_HASH160 <Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG2. 栈内执行
- OP_DUP:从栈里取出公钥,复制一份并做 HASH160(SHA-256 → RIPEMD-160),将哈希结果推入栈顶;
- OP_EQUALVERIFY:对比上一步的计算结果和 ScriptPubKey 中嵌入的 Public Key Hash,二者必须完全一致;
- OP_CHECKSIG:校验数字签名——检查提供的签名是否由对应私钥对交易内容签名生成。如果通过,则锁定脚本合法,可以花费对应 UTXO;如果不通过,交易失败。
整个过程可以概括为三步:证明公钥匹配哈希 → 证明私钥匹配公钥 → 放行资金。
五、地址生成:从公钥到 "1" 开头的地址
P2PKH 支付方式从公钥生成地址遵循以下详细步骤:
步骤 1:计算公钥哈希(HASH160)
- 计算公钥的 SHA-256 哈希值:对公钥进行 SHA-256 哈希运算;
- 计算 RIPEMD-160 哈希值:对 SHA-256 的结果再进行 RIPEMD-160 哈希运算。这两步哈希运算的结果称为公钥哈希(PKH),即 HASH160 = RIPEMD160(SHA256(pubkey))。
步骤 2:添加版本字节
在公钥哈希前添加一个版本字节:比特币主网的 P2PKH 地址版本字节是0x00,测试网是0x6f。这有助于钱包软件识别和处理不同类型的地址。
步骤 3:计算校验和
- 双重 SHA-256 哈希:对"版本字节 + 公钥哈希"进行两次 SHA-256 哈希运算;
- 取前四个字节:从双重哈希的结果中取出前四个字节,这部分称为校验和(checksum),用于检测地址输入或传输中的错误。
步骤 4:生成地址
将版本字节、公钥哈希和校验和组合在一起,整个结构为:
[version byte][public key hash][checksum]然后对整个字节串进行Base58 编码(Base58Check),生成最终的 P2PKH 地址。
示例
假设有一个公钥,生成地址的完整过程如下:
- 公钥:
022c3ee7cdb92394e32e82ec5bc8860c8888df6a9910537e90c75079726a2a8469 - SHA-256 哈希:计算结果
98a21cf747c0fcd80845afffa2260feb64aa7cc2b73ac681407b25229bad3bbc - RIPEMD-160 哈希:计算结果
999ff7726530ed0d0a7eb3b7442c5143f643f638 - 添加版本字节:
00+ [RIPEMD-160 哈希结果] - 计算校验和:对上述结果执行两次 SHA-256,取前四个字节
- Base58 编码:将最终字节串转换为 Base58 编码:
1F1J22NAAgnNHXNojT7W8GfP9JSXXjTV8N
编码细节深入
- Base58 字符集:
123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz,特意移除了视觉上易混淆的0(零)、O(大写 O)、I(大写 I)、l(小写 L),同时不包含标点符号,便于抄写与分享(详见 Base58 教程)。 - 版本字节与首字符的对应关系:
0x00前缀经 Base58 编码后以1开头,这正是"P2PKH 地址以 1 开头"的由来;同理0x05→3(P2SH),0x80→K/L/5(WIF 私钥)(详见 Base58 前缀表)。 - Base58Check 三步流程:① 给原始数据添加对应前缀;② 对结果执行两次 SHA-256,取前四个字节做校验和;③ 拼接后整体进行 Base58 编码。钱包收到地址后先解码、重算校验和比对,即可发现输入错误。
六、从地址到交易:P2PKH 的完整使用链路
支付方式总览 以 P2PKH 为例描述了从收款地址到交易完成的完整链路:
- 收款地址的获取:收款方提供一个以
1开头的 P2PKH 地址,它是经过 Base58Check 编码的、包含收款方公钥哈希的字符串; - Base58Check 解码:付款方解码地址,提取其中的公钥哈希;
- 构建锁定脚本:用提取出的公钥哈希构建 ScriptPubKey,即
OP_DUP OP_HASH160 <Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG; - 构建交易:将锁定脚本放入新的交易输出并指定转账金额;交易还需包含至少一个输入(来自付款方以前的交易输出),提供足够资金覆盖转账金额与矿工费;
- 签名和广播:付款方用私钥对交易签名,证明其有权使用输入资金,然后将交易广播到比特币网络,由矿工验证合法性并打包上链。
源码级验证:用 bitcoinjs-lib 亲手生成 P2PKH 地址
仓库中的 地址生成脚本 使用bitcoinjs-lib、ecpair和tiny-secp256k1实际演示了 P2PKH(Legacy)地址的生成:
import ecpair from 'ecpair'; import * as tinysecp from 'tiny-secp256k1'; import bitcoin from 'bitcoinjs-lib'; const { ECPairFactory } = ecpair; const ECPair = ECPairFactory(tinysecp); bitcoin.initEccLib(tinysecp); // 生成比特币私钥对 const keyPair = ECPair.makeRandom({ network: bitcoin.networks.bitcoin }); // P2PKH(Legacy)地址生成 const address = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey, network: bitcoin.networks.bitcoin }).address; console.log('Legacy Address:', address);运行方式:安装依赖npm install bitcoinjs-lib ecpair tiny-secp256k1(依赖版本参考 签名模块 package.json:bitcoinjs-lib ^6.1.5、ecpair ^2.1.0、tiny-secp256k1 ^2.2.3),然后执行node address.js。输出示例:
Legacy Address: 18RKdzEVDe6oCxrdeiipZGtKYWxTXmaxh3bitcoin.payments.p2pkh({ pubkey })这一行在库内部完成了本文第五部分描述的完整流程:HASH160 计算公钥哈希 → 拼接版本字节 → 双重 SHA-256 取校验和 → Base58Check 编码。同一脚本还演示了p2sh(嵌套隔离见证)、p2wpkh(原生隔离见证)和p2tr(Taproot)的生成方式,方便对比不同地址类型(详见 钱包脚本说明)。
源码级验证:ECDSA 签名与 P2PKH 交易构建
签名是 P2PKH 解锁脚本的核心要素。仓库中的 ecdsa.js 演示了完整的"生成密钥 → 对交易哈希签名 → 验签"流程:
const keyPair = ECPair.makeRandom(); // 模拟真实交易的哈希 const txHash = crypto.randomBytes(32); // 用私钥签名 const signature = keyPair.sign(txHash); // 用公钥验证 const isValid = keyPair.verify(txHash, signature); console.log('signature is valid:', isValid);而 ecdsaTransaction.js 更进一步,演示了构建一笔带 P2PKH 输入的真实交易:创建交易、添加输入(引用 UTXO 的交易哈希与索引)、添加输出(接收地址与以聪为单位的金额)、用私钥计算签名哈希并签名、最后把[signature, publicKey]编译成解锁脚本(bitcoin.script.compile)写入输入,输出交易的十六进制表示。
如果使用 ecdsaPSBT.js,还可以体验更现代的标准:从 WIF 私钥恢复密钥对,通过PSBT(部分签名比特币交易)添加输入输出、签名、finalize 后提取原始交易,适合多签协作等场景。
七、P2PKH 的定位与安全性总结
- 安全性:地址只暴露公钥的哈希,在花费之前公钥不公开,为持有者增加了一层隐私保护;破解公钥哈希以反推公钥或私钥在计算上不可行。
- 隐私性:相比直接暴露公钥的早期交易模式(P2PK),P2PKH 隐藏了公钥的实际内容。
- 兼容性:作为最古老的支付方式,P2PKH 地址被所有钱包、交易所和基础设施普遍支持,适合作为学习比特币脚本与交易的入门模型。
- 对比与演进:P2PKH 将公钥哈希放在 ScriptPubKey 中;而隔离见证时代的 P2WPKH(文档)将签名与公钥移至见证字段、用 Bech32 编码(教程),交易体积更小、手续费更低;Taproot 时代的 P2TR(文档)则通过 Schnorr 签名与 MAST 进一步统一了密钥路径与脚本路径的隐私。理解 P2PKH,是理解这条技术演进主线的最佳起点。
延伸阅读
- 支付方式总览与地址类型对比
- P2SH-P2PKH(以 3 开头的嵌套脚本哈希地址)
- P2WPKH(隔离见证原生地址)
- P2TR(Taproot 地址)
- Base58 与 Base58Check 编码详解
- Bech32 编码与 PolyMod 校验算法
- ECDSA 与 Schnorr 数字签名教程
- 比特币地址生成脚本(bitcoinjs-lib)
- HD 钱包与密钥派生
- 示例工程
- 区块链
【免费下载链接】Dapp-Learning
Dapp learning project for developers at all stages. Becoming and cultivating sovereign individuals. Nonprofit organization.
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考