LND 的签名能力是分层的:最上面是”给我一笔钱”这种一步到位的命令,中间是 PSBT 工作流里的补币、签名、finalize,最底下则是一个刻意做得很”生”的接口——SignOutputRaw。它来自独立的签名子服务 signrpc,0.15.0 起对外路径是 /v2/signer/signraw。低层的代价是所有约定都要调用方自己盯,收益是私钥一步都不必离开节点。本文基于 0.19.0-beta 源码讲清这个接口返回的签名为什么不是常见的 DER 格式,以及”低层”到底低在哪。
接口契约:原文进、64 字节定长签名出
proto 注释把职责说得很直白:为交易的输入输出集合生成签名,每个请求描述应如何签名、用哪些密钥、以及可选的调整量;如果无法用指定密钥签名,返回错误。请求体三块:原始交易字节、一组签名描述符(每个待签输入一份,描述用哪把钥匙、见证版本、sighash 类型等)、以及必要的先前输出。响应体只有一组原始签名字节。关键在于格式约定:返回值是固定 64 字节的签名,与闪电协议在线路上使用的格式相同——也就是 r 与 s 两个 32 字节数直接拼接。而比特币主网交易要上链,见证里装的通常是 DER 编码的签名。所以拿 SignOutputRaw 的结果直接拼进链上交易脚本前,调用方必须自己做一次格式转换,这一步源码不代劳。

”低层”的具体含义
这个接口被定位为低层构件,常规资金操作应当先考虑高层流程。低层体现在三处。其一,签名散列的计算被拆开:交易原始字节由调用方组装并保证与最终广播版本一致,签名描述符里指定的 sighash 类型也直接参与散列规则,任何一处与真实交易不一致,得到的就是一把验不过的签名,而接口本身不会替你校验。其二,密钥选择直白到底:描述符直接点名密钥定位器或脚本,没有”钱包帮你找”的环节,密钥不在钱包手里就报错。其三,产出物是裸签名:响应里的签名集合按输入升序排列,仅此而已——没有脚本、没有见证栈、没有 finalize,把 64 字节变成可广播的解锁脚本是调用方的收尾工作。还有一个随版本升级出现的硬要求:只要有一个输入花的是 Taproot(SegWit v1)输出,请求就必须带上全部被花输入的完整先前输出信息,漏带就签不了。
它存在的理由:把私钥焊死在一侧
这套接口是为远程签名架构准备的。signrpc 从设计之初就把”签名器可以独立进程”作为前提——密钥可以在远端签名服务或硬件侧,编排逻辑在外面跑。一个典型的分工是:编排器掌握交易结构、输入输出与脚本细节,签名节点只回答两个问题”这笔原文、用这把钥匙、按这个散列规则,签名拿去”。私钥从未跨进程传输,能泄露的只剩公钥与交易原文。PSBT 系列接口(钱包侧的供资、签名、完成流程)其实是同一条流水线的更高层封装,当你需要完全控制拼装过程——比如自定义脚本、外部密钥库协作、或非标准 sighash 组合——才应该降到这一层。历史 bug 也能佐证它的边界位置:0.14.3 专门修复过远程签名部署下 SignOutputRaw 不工作的回归,可见远程签名正是它的假想主场。
用之前自查四件事
一是确认转换:64 字节到 DER 的编码转换是否实现并测试过;二是确认散列:待签交易字节与最终广播字节逐位一致,sighash 类型与脚本预期匹配;三是确认密钥:描述符点名的密钥确实由该钱包持有,派生路径带 tweak 时把调整规则交给接口而不是自己心算;四是确认责任:签错的后果是交易被网络拒绝、而非资金损失的场景边界在哪里。能答齐这四个问题,再决定要不要用低层接口;答不齐,高层 PSBT 流程大概率已经够用。
风险提示:底层签名接口对调用方的正确性要求极高,错误的签名组装可能导致交易无法广播或流程卡死;涉及资金动账请先在测试网完整演练;本文不构成任何投资建议。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。