Blog

Blog / Lattice

Lattice:把身份、地址与消息历史分开

从联系人如何找到彼此、消息由谁保存出发,解释 Lattice 与 Matrix 的架构差异,以及个人节点需要面对的群状态、排序和新设备恢复取舍。

查看 Lattice 源码
更新于 9 分钟阅读9 篇参考文献LatticeRust架构设计去中心化即时通信

本文另有英文版本 Read in English

文章目录9 节

版本说明:实现部分固定在提交 50d2bb192ba842c11cca6e7f3313ff3a379f3b89。作者确认信息交换中心只记录并提供账号对应的地址/IP,不负责登录、鉴权或封禁,用户可以选择真实 IP 或中继 IP。群状态、排序和新设备恢复的具体规则仍由作者决定。

当 Alice 想给 Bob 发消息,她得先找到 Bob 的 Store。随后,系统还要说明消息经过哪些节点、由谁保存,以及 Bob 的设备依据什么接受消息。群聊又带来一道难题:如果网络分区期间两边都修改了成员状态,恢复连接后应如何处理冲突?

这些问题彼此相关,却不必由同一个服务回答。Lattice 的核心选择是把身份、位置、历史归属和消息准入分开表达。这与 Matrix 以 homeserver 与共享房间组织联邦的出发点不同,值得讨论的是它把控制权和运行责任分别放在哪里。

先看整体:谁保存什么,谁决定什么

在 Lattice 的目标模型里,Alice 与 Bob 各自持有身份密钥,并可各自运行 Store 保存自己的通信历史。信息交换服务维护账号或公钥指纹与地址/IP之间的映射,帮助联系人找到当前登记的位置。用户选择公布真实 IP,还是公布中继 IP。若使用中继,Peer 可以在路径上转交消息;它不因此成为个人历史的最终持有者。

目标架构中的身份、位置、历史与消息路径;信息交换服务位于带外发现路径。图中标签说明原型事实与候选设计。
目标架构中的身份、位置、历史与消息路径;信息交换服务位于带外发现路径。图中标签说明原型事实与候选设计。查看大图 ↗

窄屏可左右滑动查看完整结构。

信息交换服务的边界已经确定:它处理账号与地址/IP的对应关系。用户身份密钥、消息准入、设备信任和群成员状态由其他机制表达。中心验证地址声明的签名,也只说明声明与对应密钥相符,不替用户授予通信权限。

公钥指纹标识身份,地址/IP帮助定位节点,签名验证密钥持有人是否签发声明或消息,接收端决定是否接受消息,端到端加密限制中间节点读取正文。地址声明的签名不能说明节点当前在线,也不能替代接收者的准入选择。

“公开、好友申请、关闭”仍需作者定义:它们控制地址可见性、消息准入,还是两组独立选项?相应地,好友请求的送达位置、拒绝后是否仍可发现地址,以及旧地址缓存如何失效,都要有清晰语义。

地址服务失联时,系统具体会失去什么

如果 Alice 已经保存 Bob 的地址,目录暂时不可用并不必然切断 Alice 与 Bob:只要她保存的地址仍然有效、可达,而且对端 Store 正常,她可以按已有信息尝试通信。目录失联影响的是新的查询和地址更新。若 Bob 已搬迁、旧地址失效,而 Alice 又没有别的地址来源,系统就无法仅凭公钥猜出 Bob 的新位置。

地址服务属于带外发现路径,消息本身由 Store 之间投递。通信能否继续取决于保存的端点是否有效可达,以及用户是否选择中继。真实 IP 和中继 IP 对应不同的可达性、运维和网络隐私成本;具体失败后是否尝试备用路径、排队或报告未知,需要在协议和产品中说明。

固定提交没有目录冗余或自动迁移路径。设计上,中心不是消息治理者;地址查询仍是一个可用性依赖,缓存期限和地址更新流程会影响用户能否恢复联系。

Matrix 的结构差异在哪里

Matrix 本身是开放的联邦协议:不同 homeserver 可以参与同一房间,并按房间事件模型传播历史。1它的用户 ID 包含 server_name,但这个名称不是一台物理机器的 IP;Matrix 通过服务器发现和委派可以把一个服务器名映射到实际托管位置。因此,准确的比较是两套系统把身份、托管名称与通信端点放在不同位置表达。23

Lattice 把公钥指纹直接作为联系人身份的核心,并把 Store 地址作为单独的路由信息。这能让协议讨论身份密钥与节点位置时不必把它们当作同一个字段;代价是用户必须理解密钥丢失、地址失效、身份轮换和恢复之间的关系。仅保持指纹不变,并不会自动迁移历史、会话密钥或对端的地址缓存。

房间状态是另一处实质差异。Matrix 不只把消息连成 DAG,还定义事件授权依据、房间版本和分支状态解析规则。4Lattice 有 Room、成员角色、RoomEvent 和消息 DAG 的原型结构,但不能仅凭 DAG 得出各 Store 会对成员资格得出同样结论。与 Matrix 房间互通也不是把 Protobuf 转成 JSON 就能做到:还需要映射身份、权限、事件历史、密钥分享和失败语义。

维度Matrix 的做法Lattice 想探索的方向及其代价
身份与位置用户 ID 带服务器名称;服务器名称通过发现与委派解析公钥指纹与 Store 地址分开;密钥控制更直接,密钥恢复责任也更直接
历史归属同一房间的参与 homeserver 保存和传播房间事件个人 Store 更突出;多 Store 群历史怎样保持一致仍是协议问题
房间权威房间规则定义授权与状态解析可以研究更窄的个人节点/小群模型,但必须定义并发成员变更规则
设备信任规范包含设备验证、交叉签名与密钥备份机制有设备密钥和密码学组件;完整验证与恢复流程仍待组合
生态互通既有客户端、服务器和房间生态自有 Protobuf/WebSocket 协议更可控,但不直接兼容 Matrix 客户端与房间

因此,选择 Lattice 的理由应当是想研究公钥身份、个人 Store、用户可选地址与可嵌入 Rust 能力怎样组成通信系统,并愿意承担协议仍在建设中的成本。如果目标是直接使用成熟的 Matrix 客户端、加入现有房间或依赖其互操作生态,Matrix 更合适。架构选择由需求决定,不需要靠贬低另一套系统来成立。

群聊为什么不能只靠 DAG

消息 DAG 能表达一条消息的因果前序,也能容纳并发分支;它不会自动决定谁有权邀请成员、移除管理员,或分区期间哪一侧看到的是最新成员状态。设想 Alice 是群主,Bob 是管理员。网络分区后,Alice 在一侧踢出 Bob;Bob 在另一侧仍根据自己看到的旧状态邀请 Dana。两个事件都可能由对应密钥真实签名。网络恢复后,每个 Store 仍需共同回答:Bob 的邀请是否有效?撤权从哪个时点开始生效?Dana 是否已经入群?

并发成员变更的例子与两种候选路线;这不是 Lattice 已采用的状态解析协议。
并发成员变更的例子与两种候选路线;这不是 Lattice 已采用的状态解析协议。查看大图 ↗

窄屏可左右滑动查看完整结构。

候选路线之一是让所有事件先传播,再按共同的授权证据和确定性规则解析状态。这有机会让拿到相同事件集合的节点收敛,但规则必须定义基于何种历史判断 Bob 的权限,以及分区期间另一侧能否继续依据旧状态接受操作。签名只能证明事件由谁发出,不能证明签名者或接收者已经看见较新的撤权事件。

另一种候选路线是要求管理操作得到每群约定的共同确认,例如由一个明确的排序节点或 quorum 确认。这样可以为已确认操作提供共同顺序,但分区期间拿不到确认的一侧就必须暂停确认新的成员状态;quorum 的参与者、阈值、成员变更和故障行为都要定义。这不是“更去中心化”的免费选项,而是把可用性与一致性作不同取舍。

消息显示顺序需要与权限状态分开:引用回复保留因果关系,界面可以排序本地事件,而群管理可能需要共同确认。分布式系统中的因果关系本身不定义所有事件的全序。5若系统使用各 Store 的本地接收时间排列迟到消息,就要决定是否接受不同节点短暂显示不同,以及是否要求确认后的前缀保持稳定。

Matrix 的经验在于房间事件 DAG、授权规则与状态解析需要作为相互配合的机制设计。Lattice 可以先选择较窄的群功能;无论范围多大,都要明确成员变更的授权依据与分区后的状态规则。

新设备恢复:借鉴体验,不照搬成既定能力

新设备恢复至少包含三件事:证明新设备属于同一用户、把新设备需要的密钥安全交给它、决定它能恢复哪些历史。Matrix 将设备验证、交叉签名和加密密钥备份分别规定;恢复密钥能帮助解开密钥备份,却不能凭空恢复未备份的密文消息。6 设备身份恢复与新成员加入群也不同:新成员必须经过该群的准入;同一用户的新设备则需要延续用户自己的信任链。

Lattice 可以把 Matrix 式体验作为候选方向:旧设备在线时验证新设备,或在旧设备全失时用独立恢复材料找回身份与已备份密钥。最终流程仍需定义根密钥保管、设备核验、备份责任、会话密钥范围、加入前群历史的可读性,以及恢复材料遗失后的身份状态。

一份 E2EE 设计记录提出:新设备加入后不从群成员处补发旧 Megolm 会话。Megolm 的密钥轮换和历史可读性需要结合成员变化考虑。7 这可以作为“新设备默认只解密加入后消息”的候选策略,同时允许用户从自己的加密备份恢复有权持有的旧密钥。两者并不矛盾,但必须明确密钥来自哪里、谁能恢复。作者尚未确认完整恢复模型,因而本文不把这条路线写成已决定行为。

固定提交中的原型路径

一条消息从 Alice 发出时,客户端需要使用 Bob 的身份与地址信息构造协议消息。Envelope 绑定发送者、接收者、载荷和父消息等字段并由发送者签名;若载荷使用端到端加密,中间 Store 或 Peer 应当只看到密文。发送端 Store 根据接收者地址转发,Bob 的 Store 校验、保存消息,再由 Bob 的客户端同步。若地址查询失败,流程停在定位阶段;若传输失败,发送端应能区分未送达、处理中和未知结果,而不能把“我已提交”说成“对方已收到”。

固定提交中的后端 WebSocket 路径与 FFI 本地路径分开显示;FFI 的本地 send_message 不是网络发送。
固定提交中的后端 WebSocket 路径与 FFI 本地路径分开显示;FFI 的本地 send_message 不是网络发送。查看大图 ↗

窄屏可左右滑动查看完整结构。

固定提交的后端 WebSocket 路径包含消息帧处理、签名验证、联系人准入开关与限流、消息持久化、按接收者地址转发和增量同步。DAG 代码会识别缺失父消息,并有 pending/outlier 处理。Peer 有限缓存有 TTL,因此它提供的是临时中转能力,不是可靠的离线历史存储。目录服务的实现是一个 WebSocket 服务和内存映射原型;虽然类型与文档使用 DHT 命名,现有代码还不是完整的分布式 Kademlia 网络。

这里有两个容易混淆的“发送”。Store 的后端网络路径可以接收和转发 Envelope;FFI 的 send_message 则创建本地消息,写入 SQLite 并尝试索引,当前没有在该函数里建立跨 Store 的网络发送闭环。固定提交使用 vodozemac 提供的 Olm/Megolm 密码学组件;Matrix SDK 的无网络 I/O 核心和存储接口也是可参考的工程拆分。89 仓库含经 Store 的加密往返集成测试源码,覆盖特定消息路径;设备验证、跨设备密钥分享、恢复和后台投递尚未组成完整用户流程。本文没有重新运行这些测试。

原型已经能说明部分选择如何进入代码:Protobuf 定义节点间数据,Rust core 保存 DAG、Room 和接口,Store 负责服务端收发,Peer 提供短时缓存,FFI 暴露部分本地能力。代码按协议、规则、实现与装配拆分,适合继续验证不同运行形态;但当前实现仍有单一 SQLite 存储装配、后端对 WebSocket 的直接依赖、有限 FFI 路径和不完整的跨节点群状态语义。共享核心减少重复实现的可能性,不会自动完成移动后台运行、消息补偿、互操作或设备恢复。

当前排序实现以 DAG 深度、本地 Store 接收时间和哈希为键。Lamport 的因果顺序说明可帮助理解“先于”关系,但接收时间由各 Store 分别观察;这不足以证明跨 Store 的稳定全序。若产品要求确认后的展示前缀不再变化,就需要额外的排序或共同确认规则。

收益与代价

这套拆分的收益,是让身份密钥、网络地址、历史归属、消息准入、群治理和设备恢复可以分别设计。读者可以判断每项权力落在哪一层、故障时还剩下哪些路径,以及失去设备后哪些信息仍可恢复。

相应成本包括个人 Store 的运维与备份、直连暴露网络位置、中继节点的运行与保留期限、群权限的分区规则、恢复体验的密钥风险,以及自有协议缺少 Matrix 互操作生态。对嵌入通信能力的开发者,这些职责可独立组合;对只求开箱即用的用户,它们意味着更多配置和支持成本。

仍需作者明确的几个问题

  1. “公开、好友申请、关闭”分别控制地址可见性、消息准入,还是两者各有独立设置?
  2. 用户公布真实 IP 或中继 IP 时,目录具体保存哪类地址;地址过期、撤回和更新由谁确认?
  3. 群成员并发变更更看重分区期间可操作并最终收敛,还是需要共同确认后才生效?撤权延迟可以接受到什么程度?
  4. 消息排序需要所有 Store 最终同序,还是需要确认后的展示前缀永不重排?这两种承诺的实现代价不同。
  5. 新设备流程需要恢复身份、设备信任和哪些历史密钥?恢复材料丢失后,联系人看到的是身份重置还是其他恢复状态?

这些问题落到协议字段、持久化状态和用户提示上。回答它们,才能把原型里的结构变成可预期的产品行为。


固定提交与阅读入口

本文实现判断固定于 50d2bb192ba842c11cca6e7f3313ff3a379f3b89。原有逐 crate 核验和更细的源码线索保存在 docs/drafts/lattice-prototype-audit-zh.md,不作为正文的主线。

参考文献 / References

  1. Matrix.org, Matrix Specification v1.19: Architecture. Homeserver、房间事件与联邦的协议背景。 ↩

  2. Matrix.org, Matrix Specification v1.19: User Identifiers. MXID 的服务器名称空间语义。 ↩

  3. Matrix.org, Matrix Specification v1.19: Server Discovery. 服务器名称解析与委派;名称不应简单等同于物理机器地址。 ↩

  4. Matrix.org, Matrix Specification v1.19: Room Version 12. 房间事件授权与状态解析机制。 ↩

  5. Leslie Lamport, Time, Clocks, and the Ordering of Events in a Distributed System, Communications of the ACM 21(7), 1978. 因果先后关系与全序的区别。 ↩

  6. Matrix.org, Matrix Specification v1.19: Client-Server API. Cross-signing、设备和密钥备份相关规范。 ↩

  7. Matrix.org, Megolm group ratchet. 群会话密钥限制及轮换边界。 ↩

  8. Matrix.org, vodozemac documentation. Lattice 使用的 Olm/Megolm 密码学实现。 ↩

  9. Matrix.org, matrix-sdk-base API documentation. 无网络 I/O 客户端核心与存储接口的工程参照。 ↩