news 2026/10/13 4:09:02

比特币地址与签名全解:从P2PKH到Taproot与PSBT

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
比特币地址与签名全解:从P2PKH到Taproot与PSBT

说到比特币地址类型和签名方式,这几年真的可以用“三年一小变,五年一大变”来形容。早期做开发只需要记住1开头和3开头两种地址,后来隔离见证把bc1q带到台前,再后来Taproot又贡献了一个bc1p。很多人写钱包或者做离线签名时,最容易卡住的不是私钥管理,而是地址背后的脚本模板没对上:明明签名生成了,广播后却被打回;或者收款地址看着没问题,最后手续费却比预期高不少。这篇文章就是一份给开发者和进阶用户的总结,覆盖地址前缀、编码规则、脚本模板、ECDSA与Schnorr签名、多签与PSBT协作,最后放一些实际排坑经验。你可以把它当速查手册,也可以顺着章节把底层逻辑完整走一遍。

1. 四种地址类型先看清:1开头、3开头、bc1q、bc1p

1.1 地址不是账户,而是收款条件的指纹

比特币地址看起来像一串随机字符,但它本质上不是一个“账户”,也不是“钱包ID”。准确地说,地址是一种锁定脚本的可读编码。别人给你付款时,链上写入的是一个脚本,而不是“往某个账户里加钱”;将来你要花费这笔钱,必须提供一组能通过这个脚本验证的数据,通常是公钥与签名。

把地址理解为“解锁条件的指纹”会更准确。同样的私钥,如果使用不同的脚本模板,就会得到完全不同的地址。这也是很多初学者困惑的地方:同一把私钥,既能生成1开头的地址,也能生成bc1q、bc1p开头的地址,它们背后对应着不同的锁定脚本。理解这一点,后面所有内容都会顺很多。

1.2 主网地址类型速查表

我先把最常碰到的几类主网地址放在一张表里,方便随时对照:

地址类型地址前缀编码方式版本字节 / 见证版本锁定脚本模板典型用途
P2PKH1Base58Check版本字节 0x00OP_DUP OP_HASH160 <20字节> OP_EQUALVERIFY OP_CHECKSIG经典单签
P2SH3Base58Check版本字节 0x05OP_HASH160 <20字节脚本哈希> OP_EQUAL多签、嵌套隔离见证
P2WPKHbc1qBech32隔离见证 v0,20字节程序OP_0 <20字节>原生单签隔离见证
P2WSHbc1qBech32隔离见证 v0,32字节程序OP_0 <32字节>隔离见证多签/复杂脚本
P2TRbc1pBech32m隔离见证 v1,32字节程序OP_1 <32字节公钥>Taproot单签/多签/脚本路径

这张表值得多看两遍。注意最后一列“典型用途”并不是强制约束:P2SH可以装多签,也可以装其他可证明的脚本;P2WSH也一样。真正区分类型的,是中间那几列编码与锁定脚本模板。

1.3 地址类型演变的时间线

为什么会有这么多地址类型?因为每一代都在解决前一代的某些具体问题。

最早期的交易形态是“支付给公钥”,也就是P2PK。公钥本身很长,地址可读性差,也不利于隐私。后来出现了P2PKH,把公钥先做Hash160,再放进脚本,地址因此缩短到以1开头。

P2SH出现则是为了解决“复杂脚本不好用”的问题。比如要让付款方给一个2-of-3多签地址转账,如果对方必须拿到一整段完整的赎回脚本,体验和安全性都很差。P2SH允许付款方只看到20字节的脚本哈希,3开头的地址由此诞生。

隔离见证是下一个里程碑。它的核心改动是把签名等见证数据从交易的哈希计算范围中移出去,带上了“见证数据打四分之一折扣”的激励。P2WPKH和P2WSH因此被设计出来,地址使用Bech32编码,以bc1q开头。之后还有一种过渡形态,叫嵌套隔离见证,也就是P2SH-P2WPKH、P2SH-P2WSH,它们仍然以3开头,但实际使用隔离见证的验证逻辑。

Taproot则是在2021年前后正式落地的升级。它引入Schnorr签名,支持密钥路径与脚本路径两种花费方式,并让多签在链上看起来和单签几乎一样。对应的地址类型就是P2TR,以bc1p开头。理解了这条时间线,你会发现自己不是在背一堆孤立的名字,而是在看一项技术如何一步步补上此前的短板。

1.4 最容易搞混的一个点:P2WPKH与P2WSH的区别

很多人看到bc1q就默认它是单签地址,这个想法在普通钱包场景里偶尔成立,但从协议层面看并不准确。P2WPKH和P2WSH的地址前缀完全一样,都是bc1q开头,区别在于解码后得到的程序长度:P2WPKH是20字节,P2WSH是32字节。当你面对一个bc1q地址时,人眼是无法可靠区分它到底是单签还是多签的,必须用解码库去解析。开发中如果只用正则去匹配“地址是不是bc1q开头”,很容易把P2WSH当成P2WPKH处理,后续签名和费用估算都会出错。

2. 地址编码与校验:Base58Check、Bech32与Bech32m背后的事

2.1 为什么地址一定要带校验

比特币地址是给人复制和输入的,但人不是完美机器,漏掉一个字符、打错一个字母都可能导致资金进入一个无法花费的地址。校验码就是最后一道防线。Base58Check用双SHA256前4字节作为校验,Bech32和Bech32m则使用更复杂的BCH码,目的都是让常见错误大概率被发现,而不是把钱打到无人能取的地方。

有人会问:Base58Check只有4字节校验,够吗?对于抄写错误来说,32位的校验已经能挡住绝大多数情况。真正需要小心的反而是“看起来合法但并不属于你”的地址,以及测试网地址与主网地址混用,这些靠校验码无法完全解决。

2.2 Base58Check:版本字节加双SHA256

Base58Check的字符集去掉了0、O、I、l这四个容易混淆的字符。地址结构可以拆成三部分:版本字节、数据、校验码。其中校验码是双SHA256结果的前4字节,最后整体做Base58编码。

主网P2PKH的版本字节是0x00,所以地址以1开头;主网P2SH的版本字节是0x05,所以地址以3开头。测试网又是另一组版本字节。因此,地址在解码后能直接告诉你它属于哪个网络、是哪一类脚本。

下面是一段示意解码逻辑:

# 示意:Base58Check 解码 def b58decode_check(s): raw = base58_decode(s) payload, checksum = raw[:-4], raw[-4:] if hash256(payload)[:4] != checksum: raise ValueError("checksum mismatch") return payload[0], payload[1:] # version, data

版本字节的作用比很多人以为的更大。它不仅标识类型,还承担了“网络隔离”的一部分职责。如果你把一个测试网地址当主网地址广播,节点层面并不认识;即使链上侥幸打包,资金也会进入一个无法由你花费的脚本上下文。

2.3 Bech32与Bech32m:不是简单的升级关系

Bech32编码最早用于隔离见证v0地址,也就是bc1q开头的地址。它的HRP(人类可读前缀)是bc,后面用数字1作为分隔符,数据部分按5位一组编码。Bech32地址要求要么全小写,要么全大写,不能混合大小写;实际使用时基本统一采用小写。

Bech32m则是为了SegWit v1及后续版本准备的,P2TR的bc1p地址就使用Bech32m。两者的校验算法相同,只是最后的校验常数不同。为什么要单独设计一个Bech32m?因为如果v1地址继续沿用Bech32,某些特定篡改错误可能无法被检测出来,而且旧的解码逻辑也容易把新地址误判成v0。校验常数一换,两个时代的数据就自然分开了。

如果你遇到一个bc1p地址,而后端解码库仍然只实现了Bech32而没有实现Bech32m,解码会直接报校验失败。这不代表地址无效,而是库版本需要升级。处理这类问题要先看钱包或后端代码对BIP350的支持情况。

2.4 从地址还原出锁定脚本的流程

地址解析并不是“看前缀猜类型”这么简单,严谨的做法是走一遍解码流程:

  1. 根据前缀判断属于Base58Check还是Bech32/Bech32m体系。
  2. 对Base58Check地址,先解码并校验,取出版本字节和数据;版本字节决定脚本模板。
  3. 对Bech32/Bech32m地址,先校验HRP是否为bc,再取出见证版本和程序数据;见证版本和程序长度共同决定是P2WPKH、P2WSH还是P2TR。
# 示意:地址转锁定脚本 def addr_to_script(addr): low = addr.lower() if low.startswith(("1", "3")): ver, data = b58decode_check(addr) if ver == 0x00: return OP_DUP + OP_HASH160 + data + OP_EQUALVERIFY + OP_CHECKSIG if ver == 0x05: return OP_HASH160 + data + OP_EQUAL elif low.startswith("bc1"): hrp, witver, prog = bech32_decode(addr) if witver == 0: return OP_0 + prog # v0:20字节为P2WPKH,32字节为P2WSH if witver == 1: return OP_1 + prog # v1:P2TR

实际工程中不需要自己实现这些编码,成熟的开源库已经封装好,但理解流程对排查问题非常有用。很多“为什么付款方说我地址不对”的问题,最后都出在解码环节:有人用错了版本,有人把bc1p放进了老式Bech32解码器,有人把大小写混在一起导致校验直接不过。

3. 签名方式演进:ECDSA、低S值与Schnorr的取舍

3.1 ECDSA:至今仍是主流的椭圆曲线签名

比特币早期采用的签名算法是ECDSA,使用的椭圆曲线是secp256k1。ECDSA签名由两个整数r和s组成,编码成DER格式后通常有70到72字节。我们平时见到的P2PKH、P2SH、P2WPKH、P2WSH,只要它们的花费条件是“提供公钥和签名”,本质都是ECDSA签名。

理解ECDSA的关键在于:它能证明你拥有某个私钥,而不需要把私钥本身暴露出来。验证方拿到公钥、消息哈希和签名,就能完成校验。对于开发者来说,更重要的一点是生成签名时随机数k必须安全且唯一。随机数一旦重用,或者随机数可被预测,私钥就可能被直接推导出来。这不是理论风险,链上曾出现过因此泄露私钥的真实案例。

3.2 延展性问题与低S值

ECDSA有一个著名特性:签名并不唯一。同一个私钥对同一个消息,可以构造出不同的(r, s)对,而且都通过验证。第三方虽然无法伪造出“别人私钥的有效签名”,但可以在不改变交易语义的情况下修改签名形式,进而改变交易ID。

在隔离见证出现之前,这种签名延展性给上层业务带来不少麻烦。很多系统依赖交易ID作为状态流转的依据,结果广播前被第三方改了一下签名,交易ID就变了,业务状态就对不上了。BIP146提出了低S值规则,让签名形式尽量标准化,减少延展性空间。隔离见证则从结构上解决了这个问题:见证数据不再参与交易ID的计算,签名怎么变,交易ID都不受影响。这也是隔离见证带来的一个容易被忽略的重要好处。

3.3 Schnorr:为什么Taproot要换算法

Schnorr签名(BIP340)在比特币里主要服务于Taproot。它最吸引人的特性是“线性”:多个公钥可以聚合,多个签名也可以聚合。这就意味着,一个由多人共同控制的多签地址,在链上花费时可以只表现为一个聚合公钥加上一个聚合签名,看起来和普通单签几乎一样。隐私和手续费都能得到改善。

Schnorr签名的长度是固定的64字节,比ECDSA的DER编码更短更规整。它还支持批量验证:多个签名可以放在一起做一次批量校验,显著提升验证效率。Schnorr同样需要安全的随机数,尤其是聚合签名场景下,nonce的交互方式会影响安全性,所以后来又衍生出MuSig等密钥聚合协议。普通开发者不需要自己实现这些,但至少要知道:选择P2TR不代表“自动获得多签聚合”,具体还需要钱包协议层面的配合。

3.4 签名算法不是随便选的,由脚本决定

对比项ECDSASchnorr(BIP340)
签名长度DER编码,约70-72字节固定64字节
第三方延展性存在,低S值缓解基本不存在
聚合能力不支持直接聚合支持密钥与签名聚合
批量验证无支持
主要使用场景P2PKH/P2SH/P2WPKH/P2WSHP2TR及Tapscript

这里要特别强调一个容易混淆的点:签名方式不是钱包自己“选一个好看的”就行,而是由锁定脚本决定的。一个P2TR输出被花费时,验证脚本走的是Schnorr路径;如果你对这个输出强行使用ECDSA签名,它根本过不了验证。反过来,P2PKH输出的花费脚本里写的是OP_CHECKSIG,十六进制脚本的执行环境也只认识ECDSA签名。所以在排查问题时,先看地址对应的脚本类型,再判断签名算法是否匹配,顺序不能反。

4. 多签场景:地址类型如何影响脚本与协作签名

4.1 OP_CHECKMULTISIG与多签模板

比特币多签最常见的形式是m-of-n,脚本模板大致如下:

<m> <公钥1> <公钥2> ... <公钥n> <n> OP_CHECKMULTISIG

2-of-3就是m=2、n=3,表示三个公钥里至少两个提供有效签名才能花费。这个模板在P2SH、P2WSH和Taproot里都有应用,但呈现方式不同。

OP_CHECKMULTISIG存在一个历史包袱:执行时它会从栈上多弹出一个元素。所以花费方提供解锁数据时,必须在签名前面再塞一个空元素或0,否则脚本验证会失败。另一个经典坑是签名顺序必须严格对应脚本里公钥的顺序。如果你在2-of-3里用第二个和第三个公钥对应的私钥签名,但把签名顺序写反了,OP_CHECKMULTISIG照样不认。这个和“有足够数量的签名就行”的直觉完全不同,很多刚接触多签的工程人员都在这里栽过。

4.2 P2SH、P2WSH、P2TR多签,差异在哪

同样是2-of-3多签,放在不同地址类型里,链上表现和费用差别很大。

P2SH多签:地址以3开头,锁定脚本只保存整个多签脚本的20字节哈希,多签脚本本身叫赎回脚本。付款方完全不知道收款方内部是多签还是其他条件。花费时,签名方必须公开赎回脚本,并提供对应数量的签名。交易体积大,隐私一般。

P2WSH多签:地址以bc1q开头,但程序长度是32字节。多签脚本以见证脚本的形式参与验证。由于见证数据有折扣,交易体积比P2SH多签明显下降,费用更低。

P2TR多签:地址以bc1p开头,有两条花费路径。第一条是密钥路径,需要把多个参与方的公钥通过聚合协议聚合成一个内部公钥,花费时提供一个聚合签名即可,链上表现接近单签。第二条是脚本路径,可以把多签条件作为Taproot脚本树里的一个叶子,花费时揭示脚本和控制块,验证方执行里面的多签逻辑。两者各有取舍:密钥路径更隐私、更省费,但要求所有参与方配合聚合协议;脚本路径更灵活,但脚本本身会暴露在链上。

4.3 PSBT:让不同签名者协作的标准格式

多签项目里,签名的人不在一起,签名顺序也不固定。这时候PSBT就非常关键。PSBT的中文可以理解成“部分签名比特币交易”,它是一套标准格式,让多个签名者可以轮流对同一笔拟交易补充信息:你签完传给我,我再签,最后合并成完整交易。

地址类型直接影响PSBT需要携带的字段。非隔离见证输入,比如P2PKH或P2SH多签,签名者通常需要non_witness_utxo,也就是完整的UTXO交易,以便确认要花的钱确实存在且金额准确。隔离见证输入通常只需要witness_utxo,但嵌套隔离见证比如P2SH-P2WPKH或P2SH-P2WSH,还需要redeemScript,P2WSH则还需要witnessScript。如果这些上下文信息缺失,签名设备会拒绝签名,或者只能生成一种带警告的部分签名。

4.4 一个实际协作案例

我接到过一个很典型的排查请求:一个2-of-3多签地址,两位参与者签得很顺利,第三位参与者始终拒绝签名,而且不报具体原因。把未完成交易导出后对比发现,PSBT输入里只有witness_utxo和witnessScript,缺少了外层P2SH的redeemScript。第三位参与者的钱包需要完整的脚本上下文才能算出正确的签名摘要,缺失关键字段后只能选择拒绝。

补上redeemScript字段后,签名立刻正常。这类问题在PSBT协作里特别普遍,共同点是:签名算法本身没有错,错在“上下文信息不完整”。所以排查多签问题时不要一上来怀疑私钥或算法,先把PSBT字段清单过一遍。

5. 实操选型:手续费、兼容性、备份与排坑经验

5.1 地址类型对手续费的影响

比特币手续费不是由“转账金额”决定,而是由交易占用的区块字节大小决定。隔离见证引入的权重规则是:普通数据每个字节按4权重单位计算,见证数据每个字节按1权重单位计算,最终交易权重再除以4得到vsize。

下面是一组主网单签输入的常见估算值:

地址类型单签输入估算
P2PKH约148 vBytes
P2WPKH约68 vBytes
P2TR(密钥路径)约58 vBytes

实际签名长度会因DER编码产生几字节浮动,但量级差距非常明显。P2PKH输入几乎是P2WPKH的两倍多,所以同样的交易内容,用1开头地址付款和用bc1q地址付款,手续费可能差出一大截。交易输出也有差异:P2PKH输出约34字节,P2WPKH输出约31字节,P2TR输出约43字节。输出数量多的时候,P2TR的地址长度优势会被抵消不少,这一点在批量支付场景里尤其要注意。

5.2 兼容性:先问接收方支持什么

地址类型没有绝对的“最好”,只有“最合适”。个人收款,优先选P2WPKH或P2TR,省费且隐私更好。但如果你是面向商户或老旧系统的开发者,仍然会遇到只支持1开头和3开头地址的支付网关。也就是说,接收方钱包不支持Bech32时,强行给对方一个bc1q地址,结果通常是付款失败,而不是“自动转换”。

这里要特别提醒:永远不要试图通过字符替换或“格式转换”把3开头地址改成bc1q地址。地址是锁定脚本的编码,改了地址就等于把资金锁到一个完全不同的脚本上。正确做法是向接收方索要它支持的地址类型,或者让钱包在设置里切换地址格式。

5.3 地址复用与隐私

无论什么地址类型,同一个地址多次收款都会降低隐私。链上任何人都能看到这个地址收到了多少笔钱、分别是什么时间、大概从哪里来。把多笔资金汇聚到同一个地址,等于亲手把资金关系图谱送给观察者。正确习惯是每个收款场景使用新地址,这也是很多钱包默认行为。

还有一点容易被忽略:地址不是余额容器。比特币的“余额”只是钱包对UTXO集合的统计结果,一个地址可能关联多个UTXO,也可以被多个地址共同构成一笔“余额”。当你在代码里做余额计算时,脑子里要有UTXO模型,而不是传统的账户模型。

5.4 描述符备份:别只保存地址

只保存地址列表是远远不够的,尤其是多签和复杂脚本场景。P2SH多签的赎回脚本、P2WSH的见证脚本、P2TR的脚本树结构,如果丢失,即使备份了私钥,也可能无法构造出正确交易。

输出脚本描述符就是为了解决这个问题而存在的。描述符用一段文本同时表达脚本类型、密钥和派生路径,例如wpkh([fingerprint/84'/0'/0']xpub.../0/*)这类格式。文件里写下描述符和对应的主私钥或扩展公钥,恢复钱包时就不需要猜测脚本上下文。我在实际恢复案例中体会很深:只记录了几个地址和私钥,却没有保存赎回脚本,最后只能靠遍历和猜测才把P2SH多签构造出来,非常痛苦。

5.5 排错顺序:从地址到签名,逐步验证

遇到“交易被拒”的问题时,我建议按下面顺序排查:

  1. 先解码地址,确认它到底是哪一类脚本。这一步能消除一半以上的“类型猜错”。
  2. 确认UTXO确实存在,并且它的锁定脚本和本次构建脚本一致。
  3. 确认签名算法与锁定脚本匹配:P2PKH用ECDSA,P2TR用Schnorr。
  4. 确认sighash类型一致,比如SIGHASH_ALL、SIGHASH_SINGLE等。
  5. 确认PSBT字段完整,特别是多签和嵌套隔离见证场景。
  6. 广播前用本地节点或公共接口的testmempoolaccept做一次预检,而不是直接广播一个“看起来没问题”的交易。

跳过第1步或者第3步是最常见的错误来源。很多开发者拿到一个bc1p地址,先按P2WPKH去算脚本和费用,结果自然不对。把“地址解码”当成调试的第一步,你会发现大部分问题自己就现形了。

6. 收尾:我最想强调的几点经验

我在实际排查中见过太多因为搞混地址类型导致的资金卡死,归根到底都是没把“地址是脚本的编码”这个意识建立起来。如果你刚开始接触,只要记住:地址管的是“钱被什么条件锁定”,签名管的是“怎么证明你有权解锁”,两者通过scriptPubKey对账。遇到问题时,先把地址解码成脚本,再看看签名用的算法和sighash,90%的问题都能定位。

另一条经验是:不要试图把地址类型和签名方式当成两张独立的表去背。它们本来就是同一件事的两个侧面。1开头对应P2PKH,3开头对应P2SH,bc1q对应隔离见证v0,bc1p对应Taproot;ECDSA负责隔离见证之前的绝大多数签名,Schnorr负责Taproot主路径。顺着隔离见证和Taproot这两次升级去理解,比死记硬背每个版本的字节常量要高效得多。真到需要抠细节的时候,再按BIP编号查原始文档也不迟。

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

2026年Win7大神级终极版实测:老电脑续命实操指南

Windows 7还能有什么可聊的&#xff1f;正式停止支持都过去好几年了&#xff0c;官方补丁通道也早就关得干干净净。但就在2026年&#xff0c;居然还有人把Windows 7打包成一个“终极版”丢出来&#xff0c;而且版本号直接打上了“大神级”的标签。看到这个标题的时候&#xff0…

作者头像 李华
网站建设 2026/10/13 4:07:34

AnyPS5串流实战:跨设备远程游玩与延迟优化指南

1. 从“AnyPS5”这个标题说起&#xff1a;它到底想解决什么问题第一次看到“AnyPS5”这个标题&#xff0c;我脑子里蹦出来的第一个念头是&#xff1a;这大概率是一个围绕“把PS5的使用体验搬到任意设备上”做文章的项目。注意&#xff0c;这里说的不是破解、不是刷机、更不是任…

作者头像 李华
网站建设 2026/10/13 4:07:30

VCMP协议详解:VLAN自动同步的原理、部署与避坑指南

在交接网络设备维护的时候&#xff0c;我遇到过一桩怪事&#xff1a;核心交换机上明明建好了新增VLAN&#xff0c;周边几台设备上却没有。后来登进去排查才发现&#xff0c;这些设备里的VLAN配置在不停被一个叫VCMP的协议改写&#xff0c;本地手工建的业务VLAN也会无故消失。VC…

作者头像 李华
网站建设 2026/10/13 4:07:13

中港无缝清关系统底层逻辑与实操避坑指南

去年有段时间&#xff0c;我几乎每天都会接到类似的电话&#xff1a;"车到了&#xff0c;单还没放&#xff0c;能帮我催一下吗&#xff1f;"打电话的人着急&#xff0c;接电话的人更头疼&#xff0c;因为海关端的审核进度不在我们手里&#xff0c;只能干等。后来团队…

作者头像 李华
网站建设 2026/10/13 4:06:34

Java Web选课系统实战:事务、并发控制与业务规则设计

1. 网站选课系统的需求边界&#xff1a;到底要做哪些功能一提起"网上选课系统"&#xff0c;很多同学的第一反应就是"这不就是做一个课程列表加一个选课按钮吗&#xff1f;"真动手做的时候才发现&#xff0c;事情远没有这么简单。选课系统是典型的业务驱动型…

作者头像 李华
网站建设 2026/10/13 4:06:23

RouterOS WebFig汉化实战:绕过限制的前端本地化方案

简介&#xff1a;本资源是专为中文网络管理员与RouterOS初学者设计的Web界面汉化补丁包&#xff0c;解决英文WebFig界面带来的理解与操作障碍&#xff0c;显著提升中文用户对Microtik路由器系统的配置效率与使用体验。压缩包共4个文件&#xff08;257KB&#xff09;&#xff0c…

作者头像 李华