签名到底在签什么
签名的本质是“对某个摘要的私钥证明”,sighash 类型决定的就是这个摘要包含交易的哪些字段。最保守的 SIGHASH_ALL 把输入的归属、全部输出、锁定字段都纳入摘要——改动任何一处,签名作废。这层“承诺范围”在普通转账里无感,在多方合约里却直接决定攻击面:你愿意让谁、在什么范围内改这笔交易。
从平方复杂度到字段分离
历史注脚:旧式签名把整笔交易复制进摘要做双重哈希,输入越多成本越高,存在二次方复杂度问题;BIP143 为 SegWit 把摘要拆为“输入归属、锁定字段、输出、当前输入”等分项哈希,复杂度线性化,也为更细粒度的承诺组合铺路。这条演化线说明:sighash 设计史就是“让签名承诺恰好必要之物、不多不少”的取舍史,验证侧收益见 Schnorr 签名与 ECDSA 有何不同:从字节数到批量验证。
类型表的工程读法
三个基础类型加一个标志位构成主菜单。NONE 只锁定输入集合、不锁输出:同笔签名可伴随任意输出版本生效,历史上用于“签名与输出构造解耦”的众筹式模式——代价是任何经手者都能把钱收向自己,只适用于“金额换资格”的单向承诺。SINGLE 只锁本输入对应的那一个输出,其余输出可变,多输入协调场景常用;注意基础类型非 ALL 时,输入的 nSequence 不参与摘要,锁定时序语义随之变化——这直接牵连 RBF 信号的直觉,见 比特币RBF和CPFP怎么选?。ANYONECANPAY 把输入承诺交给世界:任何第三方可以追加输入、抬高手续费而保留原签名,这是“凑单”模式的骨架——共同金库向链上公告注入资金、或给交易“凑费率”,都靠它成立;风险镜像同样清楚:若合约逻辑默认“输入总额等于我方所料”,攻击者追加输入即可改变成本分摊,把别人的签名卷进自愿的混合里。
Taproot 时代的默认值
BIP341 把默认 sighash 定为 ALL(不写标志字节),ANYONECANPAY 作为独立标志位保留;ANY 前像类(ANYPREVOUT)有 BIP118 提案但截至本文核验时未在主网激活,依赖它的协议要读清部署状态,别把草案当共识。对签名设备,承诺越特殊意味着“交易内容越难被设备解析呈现”,盲签风险的源头就在这里,见 硬件钱包的小屏幕怎么读:地址回显与盲签的信任边界。
选择框架
三问定盘:这笔交易有没有对手方会在你签字后改动它?改动的哪个维度是你默许的?承诺不足(用 NONE)与承诺过死(错过协作可能)哪个后果更贵?普通用户全默认 ALL 即可;凡进入合约、众筹、凑单语境的签名,先把类型当条款读。
小结与风险提示
sighash 是签名层的“合同条款”:锁得越多越安全也越僵硬,锁得越少越灵活也越危险。任何非默认类型都应视为一次显式的授权让渡,理解让渡的范围再签字。涉及合约构造的资金存在脚本与授权风险,本文不构成投资建议。
排查协签失败时按位比对各方锁定的类型组合,比人肉比对字节流高效得多:绝大多数“签了但不合法”的案例,都是某一端悄悄换了默认类型或某处工具把 ANYONECANPAY 位吞掉了——签名有效而事务无效,正是标志位错配的标志性症状。团队里把“本流程使用哪种 SIGHASH 组合”写进交接文档,是成本最低的防事故条款。
把抽象承诺落回两个可复述的原则。原则一,签名的攻击面等于未锁定字段的编辑权:选 ANYONECANPAY 等于把“谁来付这笔”的编辑权卖给任意路由中介,选 NONE 等于把“钱去哪”的编辑权让给最后一个改输出的人——让渡前问自己:这个字段的编辑者是否值得信任、编辑结果是否在我预期分布内。原则二,验证成本与承诺粒度成反比:字段分离让节点验证更快,也让“部分签名拼装”成为可能,PSBT 流程的收益正建立在这层结构化承诺上,每方只锁自己该锁的部分,汇总后互相约束,流程见 比特币 PSBT 适合什么场景?。两条原则合起来,就是合约设计里那句老话:签最小的承诺,锁最贵的字段。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。