向对方证明“这笔钱是我付的”,常规做法是把交易哈希发给他,让他在自己的浏览器里查。‘+L(2026090505009)+’ 讲清了这套核验为什么是标准答案。但那套做法解决的是“这笔交易存在”,还剩一个更刁钻的问题:怎么证明付出这笔交易的人就是你——也就是证明你掌握过那些输入的钥匙。比特币生态为这件事设计过一套协议,编号 120,名为付款证明。这一篇讲它的结构、怎么被验证,以及它最后停在关闭状态的原因。
一份付款证明长什么样
按提案的数据结构定义,针对某笔交易 T 的证明(原文记作 PoP(T))在格式上就是一笔比特币交易:它的输入与 T 完全相同、顺序也完全相同,只是每个输入的序列号都被改成零;输出只有一个,金额为零,内容是一条 OP_RETURN 输出,装着版本号、被证明交易的哈希,以及一个随机数;锁定时间固定为 499999999。签名用的就是普通比特币交易的签名流程。于是这份证据的性质一目了然:能签出它,就等于证明了签名者当时掌握 T 全部输入的私钥——这与多签地址的关系也很自然,任何能解锁那笔交易的密钥组合都可以签,不必是当初那 M 把钥匙的同一组合。
一次完整的来回
提案画的流程有九步。服务端把一份证明请求交给钱包,请求里带三样东西:一个随机数、一个把证明送回哪里(例如一个 https 地址),以及能帮钱包定位是哪笔交易的提示,例如交易哈希、金额、标签。钱包据此找到那笔交易,找不到就让用户在匹配的几笔里挑一个;随后生成未签的草稿、请用户确认、签名并发往目的地;服务端验完回复有效或无效,钱包把这个结果原样显示给用户。规范特意注明:请求怎么送到钱包手里不在本文规定之内,那由配套的另一份提案负责。
服务端怎么判真伪
提案列的校验顺序很清楚,任何一步不过就返回无效。先看格式,要求它通过常规交易检查,唯一豁免是输入可以已经花掉;再确认锁定时间确实是那个固定的九位数;确认只有一个输出、金额为零、并且是规定格式的 OP_RETURN;确认里面的随机数和本次请求发出的一致;确认输入与那笔交易逐一对应、顺序一致、序列号全为零;然后执行所有输入的脚本,全部返回真;最后核对输出里的交易哈希正是你要问的那笔。这套设计的核心防重放手段就是那个随机数:服务端每次请求都新生成一个,偷来的一份旧证明碰上新的随机数就对不上。安全一节把暴力撞号的概率算成每次尝试 2 的负 48 次方,并建议服务端加一点延迟来压制暴力尝试,同时提醒:请求里的目的地、标签、随机数都可能被中间人改,要用安全信道,并且签字前一定要看证明内容。它还提醒钱包不应依赖自己广播时看到的那个交易哈希——如果遇到了交易可延展,服务端记录的哈希会与你手上的不同,正确做法是在网络上监听到这笔交易后再把它记进账本。
配套的链接格式
另一半问题由编号 121 的链接方案解决:它沿用支付链接 URI 的语法,但把协议头换成 btcpop,地址位置留空,并规定两个必填参数——送回哪里,以及那个随机数(随机数以 Base58 编码);另有一个可选的交易哈希参数。为了让二维码在镜头差一点的情况下也能被稳定解开,它特意把交易哈希从 64 个十六进制字符压成 Base58 的 44 个字符。它还继承了支付链接的前向兼容规则:遇到不认识的要求型参数,钱包必须判定链接无效而不是忽略。
它为什么停在关闭状态
两份文件的当前状态都是 Closed,从未成为部署的标准,今天的主流钱包不实现这套流程。原因是结构性的:付款证明要求收款方在线参与一次验证,而公开账本本身已经能证明“这笔交易存在”;在绝大多数纠纷场景里,交易哈希加确认数就够用,为此让双方再搭一套服务端和随机数机制,投入产出不划算。它也解决不了最硬的那类场景:如果付款方用的是交易所这类托管账户,输入的钥匙不在你自己手里,你的钱包根本签不出这份证明。反过来说,这套设计里最值得记住的是那个思路——把“可重复展示的截图”换成“一次性、绑定了本次请求的证据”,这个原则在今天的登录签名、扫码确认里依然是防重放的地基。
今天该怎么做
把这份提案当反面教材而非路线图:对外证明付款,仍然走交易哈希加对方自查;不接受任何声称“钱包内建付款证明”的服务要求你去签一份来历不明的东西——那份签名的结构看起来就像一笔交易,一旦签错目标,代价是真实的币。涉及地址被要求逐字符比对时,先想想地址投毒那类手法的做法,见 ‘+L(10218)+‘。以上是防御性建议,不构成任何投资、交易或套利建议;两份提案的状态以官方文件为准,核验于本文写作时。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。