持久 nonce:Solana 上的双设备签名

·阅读 7 分钟·作者:SSP Editorial Team
SSP 品牌封面,用于一篇关于 Solana 持久 nonce 与双设备签名的多签讲解文章

持久 nonce:Solana 上的双设备签名

SSP 是一个 2-of-2 钱包。每一笔交易都需要两个签名:一个来自你电脑上的浏览器扩展 Wallet,另一个来自你手机上的 SSP Key。这一设计正是关键所在——窃取了一台设备的小偷仍然无法动用你的资金。但它带来了一个非常人性化的问题。电脑在不到一秒内就构建并签署了一笔交易。手机可能还要再过两三分钟才会共同签署,因为需要有人拿起手机、查看请求、点击批准。

在 Solana 上,这段间隔是个问题。本文解释为什么会这样,以及 SSP 如何在不保存任何脆弱数据的前提下解决它。

会过期的区块哈希

每一笔正常的 Solana 交易都携带一段叫做最近区块哈希的数据。它是链上某个近期区块的指纹,同时承担两项职责。它证明该交易是不久前创建的,并防止同一笔已签署的交易被永久重放。

诀窍在于最近这个词。一个区块哈希只在大约 150 个区块内有效。在 Solana 上区块产生得很快,所以 150 个区块只相当于大约 60 到 90 秒。过了这个窗口,网络就会直接拒绝该交易——不是因为签名有任何问题,而是因为区块哈希已经过期。

现在把 SSP 的签名流程放到这只时钟面前。Wallet 构建交易、固定一个新的区块哈希并签名。随后用户的手机会收到通知。如果他们在 90 秒内回应,没问题。如果他们在开会、手机在另一个房间,或者只是想仔细阅读这笔交易,区块哈希就会悄然失效。Wallet 的签名在密码学上仍然有效,但它所附着的交易现在已经一文不值。整件事必须从头重新构建并重新签署。

对于一个签署后立即广播、一气呵成的单签名钱包来说,90 秒的窗口很宽裕。对于一个有人站在两个签名之间的 2-of-2 钱包来说,这是一场用户一再输掉的竞速。

什么是持久 nonce

Solana 对此有一个内置的答案,而且早于 SSP 出现:持久 nonce。其思路是用一个不会过期的值来替换会过期的区块哈希。

持久 nonce 存放在链上属于它自己的一个小账户里——一个 nonce 账户。这个账户由系统拥有,只保存 80 字节的数据,其中一项就是 nonce 值本身:一个长期有效、用来替代区块哈希的替身。一笔交易可以被构建为使用 nonce 账户的值来替代最近区块哈希。由于该值不会随时间失效,交易在所需的整个时间内都保持有效——几分钟、几小时、几天都行。

不过没有什么是免费的,nonce 需要一道防止重放的保护。这道保护是一条规则:任何使用持久 nonce 的交易,都必须把一个特定的指令 nonceAdvance 作为它的第一条指令。当交易最终上链时,nonceAdvance 会消耗当前的 nonce 值并将该账户轮换为一个新值。nonce 是一次性的。你周一签署的交易可以等到周三,但一旦它执行,那个确切的 nonce 就再也无法授权另一笔交易。如果你想阅读 Solana 自己对该机制的描述,持久交易 nonce 文档是第一手资料。

因此,持久 nonce 在不引入重放风险的前提下争取到了时间。这正是双设备钱包所需要的特性。

SSP 的巧思:一个你永远不必保存的 nonce 账户

持久 nonce 账户终究还是一个账户,而在 Solana 上每个账户都有一个地址。最直接的做法是在某个随机地址上创建一个 nonce 账户,然后小心翼翼地永远记住那个地址——把它写进钱包的本地存储、做好备份、指望它能在设备重置后幸存下来。这又是一件可能丢失的脆弱东西。

SSP 拒绝保存它。相反,SSP 的 Solana 多签程序包含一个名为 provision_nonce 的指令,它会在一个派生地址上创建 nonce 账户。这个地址来自一份确定性的配方:它由多签账户本身、固定的文本标签 "nonce" 以及 Solana 的系统程序计算得出。输入同一个多签,每一次都输出同一个 nonce 地址。

这一点之所以重要,是因为本系列其余部分已经确立的内容。SSP 的 Solana 多签从成员集合派生出多签地址,又从多签派生出金库地址。(如果这些派生对你来说是新概念,自启动的 Solana 多签一文会逐步讲解。)现在 nonce 账户也加入了同一个家族:它同样是一次纯粹的派生。任何 SSP 设备——你的电脑、你的手机、一个刚刚重装的钱包——都可以从零重新计算出 nonce 账户的地址。没有秘密地址会丢失,因为根本就没有保存任何地址。

这一设计还带来几点实际说明。provision_nonce 是无需许可的:任何人都可以支付那笔小额租金(约 0.00144 SOL)来让 nonce 账户存在,而支付者会成为它的初始权限方——实际上就是 SSP relay 的代付方。该权限随后可以被重新指派,而账户的地址永远不变,所以即便其背后的运营密钥发生轮换,你今天派生出的地址依然正确。nonce 账户的位置锚定在你的多签上,而非锚定在恰好为它出资的人身上。

从容的签名流程

把这些部件拼到一起,竞速就消失了。Wallet 构建一笔使用派生 nonce 账户而非最近区块哈希的交易,把 nonceAdvance 放在第一条指令的位置并签名。一条推送通知发送到手机。用户可以在自己准备好的任何时候批准——没有一只对着他们倒数的时钟。SSP Key 添加第二个签名,完全签署的交易随后被广播。由于它建立在持久 nonce 之上,它依然有效,而 nonceAdvance 会轮换该 nonce,使这笔交易无法被重放。

还有一个值得点明的约束。Solana 将单笔交易上限设为 1232 字节。一笔多签交易必须把成员列表和花费指令都塞进这个上限之内,这正是 SSP 采用 Solana 紧凑的版本化交易格式、并尽可能紧凑地传递数据的原因。持久 nonce 不会改变尺寸预算;它只改变时间预算。

万物皆派生,一无所存

这是贯穿整个《Solana 多签,以 SSP 之道》系列的主线。多签地址、保管你资金的金库,以及现在让两台设备有时间达成一致的 nonce 账户——没有一个是 SSP 必须保存并保护的值。每一个都根据钱包早已知晓的输入按需重新计算。需要备份的更少,可能泄露的更少,在设备重置时可能出错的也更少。依靠这一理念的多签设计,比如 SSP 的单签名多签方案,往往是会出故障的活动部件最少的那一种。

以与本系列其余部分相同的坦诚精神作一个收尾说明:SSP 的 Solana 多签程序目前仅部署在 devnet 上,并且在任何 mainnet 发布之前正等待一次外部安全审计。这里描述的设计——包括 provision_nonce 及其派生的 nonce 账户——是真实的,可以在开源程序中读到,但它还不是生产基础设施。如果 SSP 的双设备模型本身对你来说是新的,什么是 2-of-2 多签入门文章是起步的地方。

持久 nonce 是 Solana 一段小而古老的管道。SSP 的贡献,是让它的地址成为又一件你永远不必记住的东西。

分享本文

相关文章