news 2026/10/12 1:58:51

P2PKH 交易详解:比特币公钥哈希支付的技术原理与实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
P2PKH 交易详解:比特币公钥哈希支付的技术原理与实战
  • 示例工程
  • 区块链

【免费下载链接】Dapp-Learning

Dapp learning project for developers at all stages. Becoming and cultivating sovereign individuals. Nonprofit organization.

项目地址:https://gitcode.com/gh_mirrors/da/Dapp-Learning
点击查看免费下载

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 值)开始
21r 值长度(33 字节,含前导 0 表示正数)
00c233...e91er 值
02第二个整数(s 值)开始
20s 值长度(32 字节)
5aa5f8...7724s 值
01SIGHASH 类型

公钥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_CHECKSIG

2. 栈内执行

  • OP_DUP:从栈里取出公钥,复制一份并做 HASH160(SHA-256 → RIPEMD-160),将哈希结果推入栈顶;
  • OP_EQUALVERIFY:对比上一步的计算结果和 ScriptPubKey 中嵌入的 Public Key Hash,二者必须完全一致;
  • OP_CHECKSIG:校验数字签名——检查提供的签名是否由对应私钥对交易内容签名生成。如果通过,则锁定脚本合法,可以花费对应 UTXO;如果不通过,交易失败。

整个过程可以概括为三步:证明公钥匹配哈希 → 证明私钥匹配公钥 → 放行资金。

五、地址生成:从公钥到 "1" 开头的地址

P2PKH 支付方式从公钥生成地址遵循以下详细步骤:

步骤 1:计算公钥哈希(HASH160)

  1. 计算公钥的 SHA-256 哈希值:对公钥进行 SHA-256 哈希运算;
  2. 计算 RIPEMD-160 哈希值:对 SHA-256 的结果再进行 RIPEMD-160 哈希运算。这两步哈希运算的结果称为公钥哈希(PKH),即 HASH160 = RIPEMD160(SHA256(pubkey))。

步骤 2:添加版本字节

在公钥哈希前添加一个版本字节:比特币主网的 P2PKH 地址版本字节是0x00,测试网是0x6f。这有助于钱包软件识别和处理不同类型的地址。

步骤 3:计算校验和

  1. 双重 SHA-256 哈希:对"版本字节 + 公钥哈希"进行两次 SHA-256 哈希运算;
  2. 取前四个字节:从双重哈希的结果中取出前四个字节,这部分称为校验和(checksum),用于检测地址输入或传输中的错误。

步骤 4:生成地址

将版本字节、公钥哈希和校验和组合在一起,整个结构为:

[version byte][public key hash][checksum]

然后对整个字节串进行Base58 编码(Base58Check),生成最终的 P2PKH 地址。

示例

假设有一个公钥,生成地址的完整过程如下:

  1. 公钥:022c3ee7cdb92394e32e82ec5bc8860c8888df6a9910537e90c75079726a2a8469
  2. SHA-256 哈希:计算结果98a21cf747c0fcd80845afffa2260feb64aa7cc2b73ac681407b25229bad3bbc
  3. RIPEMD-160 哈希:计算结果999ff7726530ed0d0a7eb3b7442c5143f643f638
  4. 添加版本字节:00+ [RIPEMD-160 哈希结果]
  5. 计算校验和:对上述结果执行两次 SHA-256,取前四个字节
  6. 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. 收款地址的获取:收款方提供一个以1开头的 P2PKH 地址,它是经过 Base58Check 编码的、包含收款方公钥哈希的字符串;
  2. Base58Check 解码:付款方解码地址,提取其中的公钥哈希;
  3. 构建锁定脚本:用提取出的公钥哈希构建 ScriptPubKey,即OP_DUP OP_HASH160 <Public Key Hash> OP_EQUALVERIFY OP_CHECKSIG;
  4. 构建交易:将锁定脚本放入新的交易输出并指定转账金额;交易还需包含至少一个输入(来自付款方以前的交易输出),提供足够资金覆盖转账金额与矿工费;
  5. 签名和广播:付款方用私钥对交易签名,证明其有权使用输入资金,然后将交易广播到比特币网络,由矿工验证合法性并打包上链。

源码级验证:用 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: 18RKdzEVDe6oCxrdeiipZGtKYWxTXmaxh3

bitcoin.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.

项目地址:https://gitcode.com/gh_mirrors/da/Dapp-Learning
点击查看免费下载
上一篇:免费开源桌面分区神器:NoFences让你的Windows桌面焕然一新
下一篇:Node.js v14.13.0(Current)发布详解:CJS 命名导出静态分析、exports 通配符模式与 libuv 1.40 升级

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/12 1:58:31

UFS 3.1 UniPro协议精讲:传输层、网络层与错误恢复机制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/12 1:58:22

Page Assist:让本地大模型成为你的浏览器阅读助手

简介&#xff1a;Page Assist是一款面向Chrome浏览器的本地化AI辅助插件&#xff0c;适合需要在浏览器中快速调用大模型、管理对话与侧边栏操作的用户。压缩包内含完整可部署的插件源码与资源&#xff0c;安装时开启开发者模式后拖拽即可加载。包体共95个文件、约6MB&#xff0…

作者头像 李华
网站建设 2026/10/12 1:55:40

ESP32隐藏射频通路揭秘:从寄存器到测试模式的底层调试指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/12 1:54:37

嵌入式C与普通C的差异:内存、位运算与寄存器操作实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/12 1:53:25

AI Agent 面试题 114:Agent架构的版本管理和兼容性策略有哪些?

&#x1f525; AI Agent 面试题 114&#xff1a;Agent架构的版本管理和兼容性策略有哪些&#xff1f;摘要&#xff1a;本文深入解析了「Agent架构的版本管理和兼容性策略有哪些&#xff1f;」这一 AI Agent 领域的核心面试题。文章从 混合架构模式 的基本概念出发&#xff0c;系…

作者头像 李华
网站建设 2026/10/12 1:52:57

ESP32应用商店:MCU上的动态加载与远程行为更新实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华