2014 年春天,一家头部交易所的记账系统在处理一笔支出时,因第三方改动签名编码让交易哈希变了样,付款状态判断陷入循环,事故复盘最终指向”交易可延展性”这个词——注意它烧掉的不是密码学防线,而是”把交易身份当作唯一事实”的工程假设。此后几年,修这个问题出现过两条路线:一条是给签名定标准格式、把可改动的余地堵住,BIP-62 和 BIP-66 属此类;另一条是 BIP-140 在 2015 年 10 月提出的——既然签名可以变,那干脆在计算交易身份时把签名部分整个摘掉。作者 Christian Decker 给这个新哈希起名 NTXID(normalized transaction ID),提案是软分叉级方案,最终 Closed,但它的思路直接为后来的 SegWit 打了前站。
先把问题拆成两条来路。第一条叫第三方修改:DER 签名的字节表示不唯一(同样合法的签名可以多种编码)、脚本里有多余压栈指令的空间,旁观者不改任何金额、只重编码签名字节,序列化结果就变了,双哈希跟着变。第二条叫签名者重签:ECDSA 每次签名引入随机参数,同一个私钥反复签同一笔内容会产生不同字节,参与方自己就能制造不同的交易哈希。两条来路殊途同归:依赖这笔交易输出的下一笔交易,引用的是旧哈希;旧哈希在途中被换掉,下一笔就成了引用不存在输入的孤儿交易。BIP-62/66 路线选择逐条堵编码自由度——规范检查器越写越复杂,也始终说不清”是否堵全了”,更完全管不住签名者重签这一条。
BIP-140 的做法是在计算交易身份前,把所有输入里的签名脚本内容置空,再对剩余部分(版本号、输入出点、金额、锁定脚本、序号、锁时间)求双 SHA256。下游交易引用、签名验签都用这个归一化后的 ID。安全性论证落在签名的自我担保上:签名脚本保护的内容恰好是”剔除签名脚本后”的那部分交易数据,任何会改变 NTXID 的改动都会同时令签名失效——第三方对编码的腾挪完全落在身份之外;签名者反复重签也换不掉 ID。引用稳定了,孤儿交易问题自然消失。
那为什么 SegWit 赢了?对比要看改动面。BIP-140 要求所有涉及交易哈希的地方换算法——区块浏览器索引、钱包的确认跟踪、闪电的通道承诺、所有依赖 TXID 的合约与工具,是”改身份定义”的伤筋动骨;SegWit(BIP-141)则把签名数据挪进见证结构,让老软件眼中的 TXID 依然按老算法计算,新软件另有一个 WTXID,依赖关系的引用用前者、身份唯一性用后者。同为”把签名赶出哈希输入”的思路,SegWit 用新增结构替换而非改写语义,旧基础设施免迁移,这才是它在 2017 年胜出而 NTXID 停在 Closed 的工程原因。顺带一提,BIP-141 解决第三方修改的能力与 BIP-140 等价,签名者重签导致的 TXID 变化在两种方案里其实都防不住——闪电网络最终用清除承诺的密钥交错方案收拾这条尾巴,那是后话。
常见误区有三。其一,以为可延展性=可以偷币:2014 年那起事故里损失来自钱包实现把改动后的交易当作重复交易反复补发,延展性本身不改变金额与去向。其二,以为 BIP-66 完全没用:它规范了 DER 校验,作为中继政策沿用多年,只是没解决全部问题。其三,把 NTXID 与 WTXID 混为一谈:前者把签名摘出哈希且不保留传统 TXID,后者与 TXID 并存、把见证完整计入,方向恰好互补。
快速问答。问:今天闪电通道还受可延展性影响吗?答:通道资金安全依赖的是双方互换过的承诺交易及其密钥设计,普通第三方延展构不成威胁,这一点与 2014 年时代裸引用 TXID 的钱包处境不同。问:为什么交易所时代特别脆弱?答:因为它们的自动补款逻辑以”TXID 变了就是另一笔支出”为判断,身份与内容被绑在一起。
一条算术直觉:一笔典型 P2PKH 花费交易里,签名脚本能占到总字节数的三分之一上下——把这样一块可浮动的字节从身份哈希的输入里摘出去,等于把”身份的变动概率”直接砍到零,这正是 NTXID 想要的效果。
风险提示:本文是协议机制科普,不构成投资建议;涉及交易重发、找零与确认跟踪的开发请优先遵循现行 SegWit/WTXID 语义。

发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。