news 2026/9/22 9:42:42

Diem RecoveryAddress 模块深入解析:VASP 账户恢复机制的设计、实现与形式化验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Diem RecoveryAddress 模块深入解析:VASP 账户恢复机制的设计、实现与形式化验证

Diem RecoveryAddress 模块深入解析:VASP 账户恢复机制的设计、实现与形式化验证

【免费下载链接】diemDiem’s mission is to build a trusted and innovative financial network that empowers people and businesses around the world.项目地址: https://gitcode.com/gh_mirrors/di/diem

本篇文章基于 Diem 区块链核心框架(language/diem-framework/releases/artifacts/release-1.4.0-rc0/docs/modules/RecoveryAddress.md)及其源码 RecoveryAddress.move,系统剖析 Diem 为 VASP(虚拟资产服务提供商)设计的链上账户恢复机制:它如何通过密钥轮换能力(KeyRotationCapability)的委托,让一个"回收地址"集中托管同一 VASP 下多个账户的密钥恢复权限。读完本文,你将掌握RecoveryAddress资源的结构与生命周期、三个核心入口函数的实现细节与中止条件、MAX_REGISTERED_KEYS等关键常量的约束,以及 Move Prover 形式化规范如何保证该机制的安全属性。

一、为什么需要链上账户恢复机制

在 Diem 的账户模型中,每个账户的链上身份由其认证密钥(authentication key)决定。一旦账户持有者丢失了私钥,也就丢失了账户的控制权——除非存在一种机制,让账户所有者能够重新生成并轮换认证密钥

Diem 对此给出的答案是DiemAccount模块中的KeyRotationCapability(密钥轮换能力):它是一种可被提取、转移、存储的"授权凭证",持有该凭证的一方即拥有为对应账户轮换认证密钥的权力。而RecoveryAddress模块在此基础上更进一步,提供了面向 VASP 的多账户集中恢复方案

  • 同一 VASP 名下的多个账户,可以将各自的KeyRotationCapability委托给一个共同的恢复地址;
  • 恢复地址下的RecoveryAddress资源集中保存所有这些能力;
  • 恢复地址自身的认证密钥可以被"埋在深山里"(buried in the mountain),只有在真正需要恢复某个账户时才被取出使用。

这种设计在隔离高风险密钥与日常操作密钥的同时,保留了紧急情况下的恢复通道,是 Diem 链上账户管理体系中 VASP 侧的关键基础设施。

二、核心资源:RecoveryAddress

2.1 资源定义

RecoveryAddress是一个具备key能力的结构体,意味着它可以作为全局存储资源发布在账户地址下(见 RecoveryAddress.move):

struct RecoveryAddress has key { rotation_caps: vector<KeyRotationCapability> }

唯一字段rotation_caps是一个KeyRotationCapability的向量,存放同一 VASP 下多个账户委托过来的密钥轮换能力。该资源只能存储在 VASP 账户地址下,并且从发布那一刻起就永不删除(详见下文形式化规范中的"资源持久性"不变量)。

2.2 资源设计的两大保证

从源码注释与publish实现(RecoveryAddress.move)可以看出,该结构设计刻意保证了两个性质:

  1. 防止"恢复循环"publish强制要求资源创建者把自己的KeyRotationCapability放在rotation_caps的第一个位置(Vector::singleton(rotation_cap)),并断言该能力确实属于创建者自己(EKEY_ROTATION_DEPENDENCY_CYCLE)。这从机制上杜绝了"A 是 B 的恢复地址、B 又是 A 的恢复地址"这类循环依赖。
  2. rotation_caps恒非空:由于首个元素必然是恢复地址自身的能力,向量永远至少有一个元素,这简化了后续所有遍历逻辑与形式化推理。

三、错误码与关键常量

模块定义了一套语义明确的错误码,全部通过标准库 Errors 的错误构造器包装为对应类别的错误(invalid_argumentalready_publishednot_publishedlimit_exceeded)。下表汇总了全部错误常量及其触发场景:

常量含义对应错误类别
ENOT_A_VASP0只有 VASP 才能创建恢复地址INVALID_ARGUMENT
EKEY_ROTATION_DEPENDENCY_CYCLE1将形成密钥轮换依赖循环INVALID_ARGUMENT
ECANNOT_ROTATE_KEY2调用者没有轮换该账户密钥的权限INVALID_ARGUMENT
EINVALID_KEY_ROTATION_DELEGATION3委托双方不属于同一 VASPINVALID_ARGUMENT
EACCOUNT_NOT_RECOVERABLE4目标账户不在恢复资源中INVALID_ARGUMENT
ERECOVERY_ADDRESS5RecoveryAddress资源状态异常NOT_PUBLISHED/ALREADY_PUBLISHED
EMAX_KEYS_REGISTERED6注册的密钥数量已达上限LIMIT_EXCEEDED

此外还有一个关键上限常量:

  • MAX_REGISTERED_KEYS: u64 = 256:单个恢复地址最多可注册 256 个密钥轮换能力(RecoveryAddress.move)。add_rotation_capability在追加前会校验Vector::length(recovery_caps) < MAX_REGISTERED_KEYS,超出即抛出EMAX_KEYS_REGISTERED

四、三个核心入口函数

4.1publish:初始化恢复地址

public fun publish(recovery_account: &signer, rotation_cap: KeyRotationCapability)

publish提取recovery_account自己的KeyRotationCapability,并在其地址下发布RecoveryAddress资源。执行流程与中止条件(RecoveryAddress.move):

  1. 校验recovery_account是 VASP 账户,否则以ENOT_A_VASP中止;
  2. 校验传入的rotation_cap确属recovery_account本人(防止循环依赖),否则以EKEY_ROTATION_DEPENDENCY_CYCLE中止;
  3. 校验该地址下尚未存在RecoveryAddress资源(不可重复发布),否则以ERECOVERY_ADDRESSALREADY_PUBLISHED类别)中止;
  4. 通过move_to发布资源,rotation_caps初始化为仅含自身能力的单元素向量。

在链上脚本层,这一操作对应Script::create_recovery_address/AccountAdministrationScripts::create_recovery_address交易脚本(见 transaction_script_builder.rs 与 AccountAdministrationScripts.move)。

4.2add_rotation_capability:登记新账户的恢复能力

public fun add_rotation_capability( to_recover: KeyRotationCapability, recovery_address: address, )

将一个账户(to_recover)的密钥轮换能力加入恢复地址的rotation_caps向量。其安全约束(RecoveryAddress.move):

  1. recovery_address下必须已存在RecoveryAddress资源,否则以ERECOVERY_ADDRESSNOT_PUBLISHED)中止;
  2. 通过VASP::is_same_vasp校验to_recoverrecovery_address属于同一 VASP,否则以EINVALID_KEY_ROTATION_DELEGATION中止——这是跨实体恢复权限的硬性隔离边界
  3. 校验注册数量未达MAX_REGISTERED_KEYS,否则以EMAX_KEYS_REGISTERED中止;
  4. 通过Vector::push_back追加能力到向量尾部。

链上脚本层对应Script::add_recovery_rotation_capability(见 transaction_script_builder.rs),其错误码映射在 AccountAdministrationScripts.move 中有完整表格化文档。

4.3rotate_authentication_key:执行密钥恢复

public fun rotate_authentication_key( account: &signer, recovery_address: address, to_recover: address, new_key: vector<u8>, )

这是恢复机制的最终落点:将to_recover账户的认证密钥轮换为new_key(32 字节)。执行逻辑(RecoveryAddress.move):

  1. 校验recovery_address下存在恢复资源,否则以ERECOVERY_ADDRESS中止;
  2. 权限校验:调用者(account)必须是to_recover本人(能力原主可自行轮换)或recovery_address资源持有者(可代任何已登记账户轮换),否则以ECANNOT_ROTATE_KEY中止;
  3. 线性遍历rotation_caps,逐个比对DiemAccount::key_rotation_capability_address(cap) == &to_recover
  4. 命中后调用DiemAccount::rotate_authentication_key(cap, new_key)完成轮换并返回;
  5. 若遍历结束仍未命中,以EACCOUNT_NOT_RECOVERABLE中止。

需要注意两个细节:

  • new_key必须是 32 字节:形式化规范RotateAuthenticationKeyAbortsIf显式声明aborts_if len(new_key) != 32 with Errors::INVALID_ARGUMENT,即长度不合法时中止;
  • 只有to_recover与恢复地址持有者两个入口:规范中aborts_if !(Signer::spec_address_of(account) == recovery_address || Signer::spec_address_of(account) == to_recover)将可调用方精确限定为两者,杜绝了任意第三方借道恢复地址干扰他人账户。

链上脚本层对应Script::rotate_authentication_key_with_recovery_address(见 transaction_script_builder.rs)。

五、模块级形式化规范:用证明保证安全

该模块的最大亮点在于随源码内嵌的 Move Prover 规范spec module段,见 RecoveryAddress.move),将安全属性写成可机械验证的不变量。主要包括五类:

5.1 初始化不变量

每个恢复地址必然持有自己的KeyRotationCapability,且位于rotation_caps[0],向量长度恒大于 0。

invariant forall addr: address where spec_is_recovery_address(addr): ( len(spec_get_rotation_caps(addr)) > 0 && spec_get_rotation_caps(addr)[0].account_address == addr );

这印证了 2.2 节的两个设计保证,并使其成为全模块恒成立的性质。

5.2 资源持久性不变量

一旦地址下发布了RecoveryAddress资源,该资源在任何交易后都继续存在(模块未提供删除路径)。

invariant update forall addr: address: old(spec_is_recovery_address(addr)) ==> spec_is_recovery_address(addr);

5.3 密钥轮换能力持久性不变量

若恢复地址在更新前持有某账户的能力,则更新后仍然持有;RecoveryAddress资源本身也永不消失。

invariant update forall addr: address where old(exists<RecoveryAddress>(addr)): exists<RecoveryAddress>(addr);

5.4 资源与角色一致性不变量

只有 VASP 账户才能持有RecoveryAddress资源。

invariant forall addr: address where spec_is_recovery_address(addr): VASP::is_vasp(addr);

该不变量与publish中的ENOT_A_VASP检查形成"运行时检查 + 静态证明"的双重保障。

5.5 辅助函数与函数级规范

模块定义了三个规范辅助函数:

  • spec_is_recovery_address(addr):判定某地址是否为恢复地址(即是否存在该资源);
  • spec_get_rotation_caps(recovery_address):读取恢复地址下的全部能力向量;
  • spec_holds_key_rotation_cap_for(recovery_address, addr):判定恢复地址是否持有某账户的能力。

每个公开函数均通过AbortsIf/Ensures模式声明了完备的中止条件与后置条件。例如rotate_authentication_key的后置条件(RecoveryAddress.move)为:

ensures DiemAccount::authentication_key(to_recover) == new_key;

即"函数成功返回,则to_recover的认证密钥必然已变为new_key",把运行时行为固化为可验证的承诺。

六、模块依赖与在框架中的位置

RecoveryAddress的依赖关系(见文档头部use声明)展示了它与框架其他模块的协作边界:

依赖模块用途
DiemAccountKeyRotationCapability类型定义、能力地址查询与认证密钥轮换执行
VASPis_vasp(角色校验)与is_same_vasp(同组校验)
Errors错误码包装与分类
Signer获取签名者地址
Vector能力向量的构造、遍历与追加

其上层调用方为 AccountAdministrationScripts.move,将三个函数封装为可直接提交到链上的交易脚本;同时每个版本发布的交易脚本构建器 transaction_script_builder.rs 提供了 Rust 侧的脚本枚举(CreateRecoveryAddressAddRecoveryRotationCapabilityRotateAuthenticationKeyWithRecoveryAddress),供客户端 SDK 生成对应交易。

从发布产物看,该模块自 release-1.2.0-rc0 起即已存在(见 release-1.2.0-rc0/docs/modules/RecoveryAddress.md),并在 1.4.0-rc0 中持续提供相同接口,属于 Diem 框架中长期稳定的账户管理组件。

七、典型使用流程与安全边界总结

结合上文,一个完整的 VASP 账户恢复场景可以归纳为四个步骤:

  1. 初始化:VASP 账户 A 调用publish(链上脚本create_recovery_address),提取自身能力并在 A 下发布RecoveryAddress资源;
  2. 登记:同一 VASP 下的账户 B、C 等各自调用add_rotation_capability(链上脚本add_recovery_rotation_capability),把自身能力委托给 A(需满足同 VASP 约束);
  3. 隔离保管:A 的认证密钥私钥被离线妥善保管("buried in the mountain"),日常不参与任何交易签名;
  4. 应急恢复:当 B 或 C 的私钥丢失时,由 A(或账户本人)调用rotate_authentication_key(链上脚本rotate_authentication_key_with_recovery_address),将目标账户认证密钥轮换为新密钥。

该机制的安全边界可以凝练为三点:

  • 同 VASP 隔离:恢复能力只能在 VASP 内部委托,跨 VASP 委托被EINVALID_KEY_ROTATION_DELEGATION强制拒绝;
  • 双入口调用:只有能力原主与恢复地址持有者可以触发轮换,第三方无法干预;
  • 能力集中、密钥分离:多个账户的恢复能力集中在单一地址,而该地址的高权限密钥独立保管,实现了"日常低风险操作"与"应急高权限操作"的物理隔离。

【免费下载链接】diemDiem’s mission is to build a trusted and innovative financial network that empowers people and businesses around the world.项目地址: https://gitcode.com/gh_mirrors/di/diem

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/22 6:20:41

ESP32双网络语音识别实战:唤醒词与命令词协同架构设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/22 6:19:32

国产AI生成PPT动画实测:效率提升10倍?以YOLO讲解为例

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/22 1:04:59

ABAP源码解析实战:SCAN ABAP-SOURCE自动化技巧

1. 从重复劳动到自动化&#xff1a;ABAP源码解析的实战技巧在SAP项目实施过程中&#xff0c;我们经常会遇到需要从大量ABAP代码中提取特定信息的场景。以我最近处理的CRM工单流程代码为例&#xff0c;include程序LCRM_ORDER_OWF03包含了608行状态判断逻辑&#xff0c;其中分布着…

作者头像 李华
网站建设 2026/9/22 1:01:43

PyTorch张量基础与高效操作指南

1. PyTorch 张量基础概念解析PyTorch 张量&#xff08;Tensors&#xff09;是现代深度学习框架中最基础的数据结构&#xff0c;也是构建神经网络模型的基石。作为从 NumPy 数组演化而来的多维矩阵&#xff0c;张量不仅继承了 NumPy 的高效数值计算特性&#xff0c;还增加了自动…

作者头像 李华