MATRIX X · PRIVATE COMMUNICATION INFRASTRUCTURE · 基础工程 16 / 16 · 全局迁移工程 15 / 15
隐私,不是一个开关。
是下一代通信底座。
让服务器可靠运送消息,但不再长期保存聊天历史。E2EE 进一步让服务器连投递中的正文也无法读取;两条边界不能混成一个开关。
当前真实进度:Private Chat 基础与全局本地优先迁移工程均已收口,L01–L15 为 15 / 15。真人 TestFlight、10 天观察、S3 生命周期和分阶段灰度已延期;当前尚未上线 E2EE,生产密文运行时与用户入口仍关闭,资源和旧历史物理删除均未开始。
THE INVESTMENT CASE
把隐私能力,
变成产品护城河。
我们不是为一张“已加密”徽章投入,而是在已有 IM 上建立一条可审计、可扩展、可随时停止的信任基础设施。
把信任写进基础设施
私密通信不是一枚营销标签,而是账号、设备、消息与媒体共同遵守的系统边界。它让安全承诺可以被验证,而不是被相信。
不重造 IM,只重画信任边界
保留现有登录、聊天、推送和 S3 资源底座;客户端掌握密钥,服务端收缩为授权、盲路由与可靠投递。
代码完成不冒充产品上线
工程能力已经收口。当前没有真实用户,真人试点、十天观察、生命周期和分阶段灰度延期;观测与停止能力继续保留。
真正的差异化,不是服务器承诺不看;
而是架构让它根本看不了。
ARCHITECTURE · ONE SCREEN
一张图看懂:
谁拥有明文,谁永远不能拥有。
服务器没有消失。它仍负责授权、限流、排队、重试与可靠投递,只是被明确排除在解密边界之外。
发送方 iOS
- 生成与保存私钥
- 加密消息与媒体
- 逐设备生成 envelope
看得见投递,看不见内容
可见:公开密钥、设备 ID、必要路由元数据
不可见:正文、私钥、会话状态、媒体 key
接收方 iOS
- 验签与解密
- 原子推进 ratchet
- 本地安全落盘
端上拥有内容服务端拥有可靠性但没有解密能力
HOW A MESSAGE MOVES
一条消息,六个不可跳过的安全动作。
每一步都保留恢复能力,但没有任何一步允许服务端拿到正文。
- 01
确认设备
读取已授权设备与签名预密钥,不向服务端索取私钥。
- 02
本地建链
在发送设备内建立独立会话,为每台目标设备生成不同密文。
- 03
密文入队
盲信箱只保存 envelope、TTL 与最小投递元数据。
- 04
通用唤醒
Push 只说“有新消息”,不携带正文、预览或媒体地址。
- 05
设备解密
接收设备验签、解密并原子推进 ratchet,失败绝不回退明文。
- 06
落盘后确认
消息和状态安全落盘后才 ACK;重试不会制造第二条消息。
L09 · DEVICE-TO-DEVICE HISTORY MIGRATION
历史不在云端。
换设备也不丢失。
Matrix X 不把聊天数据库变成永久云备份。旧设备直接把本地唯一历史加密交给新设备;服务端只做 24 小时盲中转,既看不到内容,也拿不到迁移密钥。
旧设备
生成一致性快照、分片加密和 Manifest;原历史不会因迁移自动删除。
S3 · 24h
- 服务器密钥
- 0
- EC2 资源字节
- 0
- 生产会话
- 0
im-core 仅保存会话、分片状态和密文摘要;运行开关保持关闭。
新设备
只补缺失分片;全部通过摘要与认证标签后,才一次性提交本地数据库。
- 01
新设备出示一次性二维码
二维码只携带迁移声明和 32 字节端到端迁移秘密;服务端拿不到秘密,也不能替设备批准。
- 02
旧设备核对并授权
来源设备显示目标设备、账号和有效期,用户确认后才建立迁移会话;撤销设备不能继续上传或下载。
- 03
本地导出并分片加密
本机数据库生成稳定快照,按不超过 2 MiB 明文分片独立加密,并把顺序、摘要与 Merkle 根绑定进 Manifest。
- 04
S3 盲中转 24 小时
设备凭预签名票据直接上传密文;im-core 只保存状态和密文索引,EC2 不持久化资源字节。
- 05
断点续传与完整性复核
新设备仅补缺失分片;任一长度、摘要、认证标签或根摘要不一致,整批拒绝,不导入半份历史。
- 06
原子导入后回执删除
全部验证通过才一次性切换本地历史;ACK 后回收中转对象,来源设备原历史保留,直到用户自行处理。
L11 · LEGACY HISTORY RETIREMENT
服务器旧历史,
不是说删就删。
先让设备证明自己拥有完整、可恢复的本地副本,再从真实 ACK 开始观察至少 90 天。当前线上只有证明能力,没有迁移流量,更没有删除接口。
设备本地归档
独立 SQLite 与冷存储先成功落盘,再推进检查点;不会把旧历史灌进热列表。
SHA-256
- 跨端摘要
- 1
- 观察期
- 90d
- 删除条数
- 0
im-core 只核对稳定清单、精确回执与观察状态;数据库约束锁死删除事实。
生产零迁移
能力关闭、试点账号 0、四条路由 404;90 天计时尚未开始。
- 01
冻结旧历史清单
im-core 为账号生成稳定边界、数量与摘要;迁移期间的新消息不混入旧快照。
- 02
每页最多 200 条
iOS 后台有界读取,避免一次装入全部历史,更不会逐条刷新当前聊天列表。
- 03
先落本地再记断点
消息先进入独立 SQLite 与冷存储;只有持久化成功后才推进受文件保护的检查点。
- 04
跨端精确证明
Swift 与 Go 对同一规范化清单计算 SHA-256;数量、边界或任一内容不一致都拒绝 ACK。
- 05
ACK 启动 90 天观察
观察期从真实完整回执开始,不能从代码合并或暗部署日期倒推。
- 06
删除另行授权
当前控制面只生成待回收证据,没有删除接口;生产删除事实始终为 false、false、0。
ENGINEERING CLOSEOUT · RUNTIME DEFERRED
工程已经收口,
运行门按需恢复。
EC2 已运行统一门禁与观测合同,当前仍是 phase=disabled、ready=false。真人验收、十天观察、生命周期和灰度延期,不再占用工程刀数。
工程收尾
15 / 15L01–L15 代码、交互、协议、媒体、停止与回滚已经进入主线。
真人验证
延期TestFlight 双账号和双物理设备以后按真实用户窗口恢复。
分阶段灰度
延期当前无真实用户,不维护 2 人到 20 人的阶段账本。
资源生命周期
延期S3 生命周期不执行,物理删除继续关闭。
Private Chatfalse
普通消息本地优先false
设备历史迁移false
资源物理删除false
旧历史删除false
门禁判定gate_evaluated
会话打开conversation_opened
发送成功message_send_succeeded
发送失败message_send_failed
接收成功message_receive_succeeded
接收失败message_receive_failed
迁移成功history_migration_succeeded
迁移失败history_migration_failed
停止触发stop_triggered
出现明文 canary、解密完整性失败、跨账号数据、迁移损坏、不可恢复崩溃或门禁事实不一致时,立即停止并回滚;不得以“继续观察”掩盖安全异常。
99c0d6f761bfmatrixx.local-first-pilot/v1matrixx.local-first-pilot-signal/v1identity=false · content=falseL13 · GROUP E2EE PROTOCOL POC
一个群,一份密文。
成员变化,整群换纪元。
发送方每个安全纪元只加密一次;成员变化先冻结发送、轮换纪元,再允许新密文进入盲中继。
matrix-sdk-crypto-ffi 0.17.0逐设备 Olm 扇出
群规模增长时,每条消息都要为每台设备生成密文,成本和失败面随设备数线性增长。
Matrix 群组会话
与现有官方 Matrix Crypto FFI 同源;三设备、两纪元、乱序、篡改、退群隔离已在隔离 POC 通过。
Messaging Layer Security
后妥协安全更强,但当前没有完成审查的 shipping Swift / FFI 接线;留作协议升级路径。
- 01PREPARE
校验操作者权限、二级确认、协议支持和唯一可信设备名单。
- 02DRAIN
Outbox 与媒体任务必须排空;任何未完成投递都阻止切换。
- 03EPOCH 1
首个群组会话激活;服务端只协调公开 epoch 与 roster 摘要。
- 04ROTATE
加人、退群、设备变化或周期阈值触发冻结,并且只允许精确 +1。
- 05EPOCH 2
新纪元恢复发送;已移除成员不能解密之后的消息。
Alice、Bob、Charlie 分别持有本地密码状态
成员变化后完成精确 +1 切换
乱序、篡改、重放和退群隔离全部通过
密文与公开协调状态未命中明文 canary
选择可交付路线,不包装成算法胜利。
- Megolm 不是“比 MLS 更安全”;本期选择基于当前代码、官方引擎和一人团队的可交付性。
- L13 只证明协议与公开协调状态机可行,不包含群聊 UI、密钥分发、生产路由或数据库接线。
- 成员变化期间必须冻结发送;旧纪元密文不能伪装成新纪元继续投递。
群聊产品入口false
运行路由0
数据库迁移0
生产 E2EE 群0
正式进度推进false
0d42acfcb5fd27babaaf0e965b008e6fa7ad15 / 15 · 已收尾L14 · PRODUCT MESSAGE ROUTING
一条消息,只有一条权威道路。
客户端不再自己猜“这个群是不是加密”。每次进入消息链路,都先读取服务端认证后的安全状态;一旦受保护,旧明文道路永久失效。
普通群
standard继续使用普通本地优先链路;不会因客户端猜测而升级。
加密群 · active
encrypted只允许 Megolm 密文;正文、受保护历史和待发事实留在设备本地。
准备或轮换中
blocked冻结发送,等待新 epoch 与设备名单完成;绝不临时回退旧明文接口。
54d1e0459fa9314b4b048880135 pass · 0 fail15 / 15 · 已收尾iOS PR #193 · 013def7ab7c2im-core PR #247 · 明文围栏im-core PR #248 · 权威路由中文验收 496
L14 · ENCRYPTED PRODUCT CONTENT
真实聊天语义,
也不能泄露给服务器。
回复关系、@ 对象和静默意图不是“顺手加几个服务端字段”。它们先在设备端组成稳定负载,再整体进入群密文;im-core 继续只看见不透明信封。
TEXTREADY文字
正文进入版本化应用负载,再交给 Megolm;旧版未包裹文字仍可投影。
REPLYREADY回复
回复标识与当前正文一同加密,本地历史解密后恢复引用关系。
MENTIONREADY@ 提及
目标、角色与显示名在端侧校验;重复、冲突或正文无令牌时拒绝发送。
SILENTPARTIAL静默意图
is_silent 已进入密文;通知消费端尚未接线,不能宣称静默行为完成。
L14 · ENCRYPTED MEDIA RESILIENCE
弱网中断,
不必从零开始。
图片、GIF、语音、视频和文件先在设备端成为密文。下载中断后,客户端只信任已经复核的完整密文分块;服务器无需新增资源字节副本、数据库长任务或解密能力。
任务目录只使用不可逆摘要;checkpoint 不保存 token、票据、签名 URL、资源原值或媒体密钥。
恢复前核对描述符、文件长度、完整分块边界与已提交密文前缀 SHA-256;不一致时在发起网络请求前失败。
每个 Range 完整同步落盘后才推进 checkpoint;网络中断只重取剩余密文字节,不重复下载已验证分块。
401/403 最多重新申请两次下载票据,签名 URL 永不落盘,S3 请求也不携带 App Authorization。
全部分块完成后仍复核完整密文 SHA-256,再执行逐块认证和解密;断点不能替代最终完整性。
L14 · DURABLE PERIODIC ROTATION
密钥不会永久有效。
时间与消息量,谁先到谁换钥。
每台设备各自计数必然分叉。Matrix X 让 im-core 只保存公开 epoch 窗口,让端侧继续独占真正密钥:服务端裁决“旧 key 还能不能用”,设备完成新 key 的生成、分发与本地保存。
PUBLIC WINDOW ONLY · SERVER KEY COUNT 0 · PLAINTEXT COUNT 0
- 01建立窗口
新 epoch 提交时原子写入 count=0 与 24 小时截止时间。
- 02只数已接收
每个新幂等键成功接收一次才加一;网络重试回放原回执。
- 03第 100 条成功
消息先完成服务端接收与本地耐久提交,再标记必须换钥。
- 04后台换钥
端侧生成新 sender key,精确分发给当前可信设备并提交新 epoch。
- 05第 101 条封锁
若后台换钥失败,专用 423 阻止旧 epoch 继续发送,绝不回退明文。
- 06同一消息恢复
只丢弃未接收 prepared 密文;以同一 messageID 在新 epoch 下重封装。
只会有一条成为第 100 条
计数与截止时间不会归零
同一请求不会重复计数
成功消息不会被误删重发
L14 · ONE COHORT, ONE SAFETY LOOP
只保留一套真人队列,
把群聊风险接回统一停止控制。
这不是再造一个运营后台。L14 必须与 L12 使用完全相同的 revision 和账号集合;任一漂移都在进程启动时失败关闭,公共 meta 不暴露账号主体。
同 revision · 同账号集合
子集、超集、空 revision 和 L12 未就绪全部拒绝;不存在“群聊先给部分人偷偷打开”。
4 类固定低基数信号
group_delivery · group_decrypt · group_epoch_transition · group_media
52 / 53 通过
0 失败、1 条既有条件性跳过;架构门禁 117 / 117,iOS 必需状态 8 / 8。
默认关闭 · 独立启用
configuration ready=false · runtime=false · shipping=false;真人 TF、10 天观察和分阶段灰度已延期。
生产收敛
代码已经收口。运行验证按需恢复。
“工程完成”“生产关闭”“运行延期”分开显示,不把延期冒充验收通过。
后端已对齐生产,iOS 已进主干
b900bf559956 · iOS #238–#241 · 生产关闭。
代码已合并,生产等待授权
主干 64c7b7c05e60 · 生产 8d3a9c615af7 · AWS 替换 0 · 删除关闭。
REALITY, NOT THEATRE
安全底座完成。
全局迁移工程 15 / 15。
旧 K01–K16 证明 Private Chat 的协议工程基础;L01–L11 完成本地优先、单聊密文、设备迁移、十二类资源治理和旧历史回收控制。L12 完成统一准入、观测、停止与回滚;L13 完成 Megolm POC;L14 将权威路由、换钥、文字语义、五类密文媒体、后台当前分块、主动控制、7/127/2500 群规模和双模拟器验收接入主线;L15 的群主/有权限管理员直接开启 UI 也已合并。真人 TestFlight、10 天观察、S3 生命周期与分阶段灰度延期。生产 shipping、密文运行时、迁移与删除继续关闭,是否全量开启另行决定。
L11 真实验收:iOS PR #158 · im-core PR #231 · EC2 a17d5e5b9383 · 200 条分页 · 90 天观察 · 路由 404 · 表 0/0 · 删除 false/false/0 · 中文验收 489
L12 控制面:iOS PR #164 · im-core PR #237 · EC2 99c0d6f761bf · Knowledge b7a03e85c59e · phase disabled · ready false · 账号 0 / 2 · 观察 0 / 10 天 · 中文事实 494
L13 并行 POC:iOS PR #165 · im-core PR #238 · m.megolm.v1.aes-sha2 · 三设备 · 两纪元 · 56 / 56 + 4 / 4 · 中继明文 0 · 产品入口 false · 生产群 0 · 中文验收 495
L14 文字产品路由:iOS PR #193 · im-core PR #248 · iOS 54d1e0459fa9 · im-core 314b4b048880 · plaintext fallback false · shipping false · 权威安全上下文后端已暗部署、iOS 已合并 · 中文验收 496
L14 可信换钥链:iOS PR #195 · im-core PR #251 · iOS 3092e28a0e76 · im-core / EC2 8b78656edf73 · 四类原因 · stable change_id · notification wake-only · shipping false · 中文验收 498
L14 周期换钥:iOS PR #197 · im-core PR #252 · 24 小时或 100 条 · 第 100 条成功 / 第 101 条 423 · iOS 729667f00e9d · im-core / EC2 07974ea14207 · 五角色 · 窗口 0 行 · 四路 404 · shipping false · 中文事实 499
L14 统一试点与观测:im-core PR #261 · iOS PR #226 · 后端 / EC2 b020b29b3dce · iOS ad1bd6ed4189 · Knowledge a1b99c2191bc · 同 revision / 同账号集合 · 四类匿名信号 · ready false · 账号 0 · 中文事实 516
L14 加密内容语义:iOS PR #199 · 文字 / 回复 / @ / 静默意图进入同一密文负载 · iOS 9767b4c51947 · 19 / 19 · 架构 117 / 117 · 服务端明文字段 0 · 静默通知消费作为后续增强,媒体由事实 507 接续 · 中文事实 500
L14 密文媒体恢复:共享 SDK PR #4 · iOS PR #207 · 五类媒体真实收发入口 · 无敏感值任务账本 · 64 KiB checkpoint · 完整分块续传 · 401/403 最多续票两次 · 最终密文 SHA-256 · SDK 36 / 36 · iOS 8 / 8 · 后续已完成当前分块后台收发和主动控制,整对象杀进程后自动串行仍延期 · 中文事实 507
K16 基础证据(历史):PR #186 · 51b009e · im-core · K16 试点白名单与路由修复 · PR #129 · 28250b7 · iOS · K16 试点判定器 · PR #131 · 2d4bb93 · iOS · 单一 Shipping 产品 · PR #133 · 4040f20 · iOS · Shipping 产品进入 App 编译图 · PR #134 · f7e513f · iOS · 发布输入中文路径恢复 · Run #82057 · 路径守卫通过 · 发布编排 · 精确源码输入 · PR #27 · 5ddda97 · 发布编排 · Runner 隔离身份合同修复 · PR #101 · 1c867f0 · Knowledge · 472 中文母版接线事实
历史四仓同构契约:1a8ce8b90ec8
ENGINEERING EVIDENCE · K03—K16
下面不是愿景。
是可以逐项复核的工程事实。
协议、设备身份、预密钥、会话门禁、盲信箱、iOS 状态机、密文媒体、多设备投递和试点门禁,全部保留到实现与证据层。
K03–K04 · PROTOCOL + STATE POC
协议能分发,还要真的扛住失败路径
K03 解决许可证与 iOS 分发,K04 用官方引擎验证 Olm 状态机。通过只代表允许设计设备身份,不代表产品入口或生产链已经可用。
K04 Olm 隔离 POC 通过 · 生产 No-Go
选中候选 matrix-sdk-crypto-ffi 0.17.0 · m.olm.v1.curve25519-aes-sha2 · Apache-2.0
- 自动证据
- 三设备状态机 PASS · iOS 16 arm64 编译 PASS
- 边界
- K04 当时只放行 K05 设备身份设计;K16 已进入 App 编译图,但运行门禁和产品入口仍关闭
- 制品 SHA
7d5e15e072eccb8c
每个目标设备独立 ratchet;已消费密文重放不返回正文。
群组房间会话需调用方另建 sender key / session / message index 重放账本;高层 FFI 不代管该账本
Bob 两条消息逆序到达,均各解出一次
不返回正文,不污染后续合法状态
已消费 Olm 密文不能再次得到明文
Bob 密文投给 Charlie 不返回正文
关闭并重开 store 后 ratchet 可继续
中继数据不含四段测试正文
| 候选 | 许可证 | iOS / 维护事实 | 结论 |
|---|---|---|---|
| Signal libsignal | AGPL-3.0 | 第三方使用与消费方 SwiftPM 不受支持 | 当前生产 No-Go |
| vodozemac 直连 | Apache-2.0 | 无官方 Swift 消费包,需要自管 Rust FFI | iOS 分发 No-Go |
| OpenMLS | MIT | iOS 只构建不测试,且是 MLS 群组协议 | 首版协议不匹配 |
| Matrix Crypto FFI | Apache-2.0 | 官方静态 XCFramework;Olm 三设备状态机与失败关闭已验证 | K04 隔离 POC 通过 |
iOS main 已完成单一 Shipping 产品和 App 编译接线;K04、K06–K16 的工程能力已经收口,但尚未启用 Private Chat 产品入口。 K09 后端运输面继续默认关闭;K14 已补齐 S3 密文资源,K15 已补齐新消息多设备。签名 TestFlight 与真人运行验证已经延期,不再阻塞工程收尾;生产是否开放是下一次独立产品决策。
K05 · CRYPTO DEVICE AUTHORITY
登录设备不等于密码学设备
K05 把账号主体、登录会话、登录/Push 设备和 Private Chat 密码学设备拆开。客户端持有私钥;Auth 只签发公共准入/撤销事件;im-core 只验证和投影。
账号主体
reits-auth 的稳定用户身份,不包含聊天私钥。
Auth 登录会话
可撤销的账号会话,只能申请一次性注册挑战。
登录 / Push 设备
服务普通登录与通知,不能直接充当 E2EE identity。
密码学设备
客户端生成 Ed25519 / Curve25519 私钥;公钥换代创建新 ID。
私钥、Olm pickle、消息与媒体 key 永不上传。
5 分钟挑战、候选设备签名、强认证/已有设备授权、完整请求幂等。
Authority 签名失败关闭;revoked 设备立即退出未来投递集合。
K06 · PREKEY LIFECYCLE
离线首次建链,先把“一把钥匙只能领一次”做对
接收方不在线时,发送方只能领取公开 Prekey。K06 把设备准入、签名、过期、库存和并发语义冻结成 iOS / im-core 同一份机器契约。
公开 publication 不含身份、signed/one-time 私钥,也不含正文或消息 key。
Ed25519 分别签名,避免字段混签,signed prekey 可独立验真。
publisher、requester、target 的 generation 必须和公共身份投影一致。
同 ID 不同请求拒绝;空库存、过期、撤销、篡改全部失败关闭。
1 次成功 · 23 次库存耗尽 · 0 次重复分配
contract sha256 · 1a8ce8b90ec8382938462489742484bf48184b3fdae28398a435453ef41562feK07 · PRIVATE_V1 CONTRACT
不是打开一个开关,而是五类事实同时成立
K07 先冻结独立会话和信封,再允许 K08 建表。普通聊天不能原地升级;远程 Feature Flag 只能表达服务端能力,不能替代客户端就绪度、双方白名单或证据新鲜度。
K12 隔离本地保护已通过,但 shipping App 仍固定 false;K16 试点硬化前不能放行。
private_chat_v1 只是一项服务端能力声明,默认 false。
真人批准的账号范围;缺失或撤回立即停止新建。
双方都必须获准,不能把未授权用户被动拉入试点。
能力与白名单 revision 必须存在且未过期。
CLIENT ∧ SERVER ∧ INITIATOR ∧ RECIPIENT ∧ FRESH全部为真才创建任一缺失 / false / 过期 → DENY · 不产生部分会话private_v1
- 协议
- m.olm.v1.curve25519-aes-sha2
- 参与者
- 恰好 2 个账号
- 旧会话升级
- DENY
- 并发重试
- 24 次只产生 1 条
ciphertext-envelope/v1
- 密文上限
- 64 KiB
- 最长 TTL
- 14 天
- 签名
- 发送设备 Ed25519
- 未知字段
- DENY
明文不可表达
消息正文、消息 key、Olm pickle、身份/Prekey 私钥、媒体 key、Push 预览、可搜索消息内容。
private_conversation
两条参与者记录
创建幂等记录
门禁快照摘要
无正文审计事件
K08 · BLIND MAILBOX
服务器可以排队与确认,但数据模型不允许它读正文
K08 交付的是可审阅存储内核,不是已上线功能。12 张专用表只表达公开键、路由、密文、序号、TTL、ACK 和无正文审计。
先交付公开 OTK
串行化领取一把 available OTK,相同 request 重试返回同一 reservation。一旦对外交付,这把键就绝不再分配给其他建链者。
再原子提交首密文
一个 SERIALIZABLE 事务同时写会话、参与者、幂等事件、OTK committed、设备序号、密文和无正文审计。
AVAILABLE→RESERVED→COMMITTED或ABANDONED · PERMANENTLY BURNED无任何路径回到 AVAILABLE;宁可浪费公开 OTK,也不允许键重用。密文排队与设备隔离
按接收账号 + crypto device + generation 分区;序号单调;撤销设备不能 reserve、enqueue、pull 或 ACK。
先耐久提交,后签名 ACK
乱序页先排序;全页新密文本地事务成功后才推进游标,产生 SHA-256 commit digest 和 Ed25519 ACK。
任何失败都不得回退明文
本地落盘失败不前移游标、不生成 ACK;跨设备 ACK、冲突重放、篡改和 generation 不一致全部拒绝。
K09 · CIPHERTEXT TRANSPORT
实时和 Push 只负责叫醒,盲信箱才是真相源
六条严格 HTTP 路由承载 reserve、commit、send、pull 和 ACK;WebSocket 只发 K07 密文信封;Push 只发两项通用唤醒字段。
先写盲信箱
密文与单调序号进入 PostgreSQL 后才通知。任何实时或 Push 故障都不能撤销已经成立的消息事实。
断线统一补拉
重复帧忽略,序号缺口、重连和回到前台都触发 K08 不透明游标 pull;WebSocket 本身不推进耐久游标。
身份与结构双重失败关闭
Bearer 账号必须等于业务主体;非 JSON、尾随 JSON、未知字段、跨账号 reserve/send/pull/ack 全部拒绝。
可以携带 envelope,不能携带正文
分角色部署通过 Redis Bus 转发密文帧;投递失败后按 HTTP cursor 恢复,不另造第二套消息真相。
无标题、正文、身份和 URL
发送者、会话 ID、envelope、ciphertext、媒体 URL 任何一个出现都不符合 K09 契约。
K10 · IOS CRYPTO ADAPTER
业务只提交消息,密码状态只有一个主人
K10 不再让业务代码碰 OlmMachine、Curve25519 私钥或 Ratchet 状态。单一 Swift actor 负责公钥操作、逐设备密文、K07 签名信封、解密和重放防线。
先入盲信箱,再推进 Olm
Adapter 先返回 K07 签名密文;只有 K09 盲信箱明确耐久接受后,业务层才能提交出站密码状态。
先落重放账本,再返回正文
验签、设备绑定和 Olm 解密通过后,先原子写入 envelope 摘要;写失败不返回正文并停止 Adapter。
公开操作与受控结果
公钥目录请求、K07 密文信封、耐久后 commit、验证且落账后的私密文本。
句柄不可编码、不可导出
业务拿不到签名私钥、store 口令、Olm session 或 Ratchet;K12 已在隔离层补齐 Keychain 与文件保护装配。
跨库恢复已由 K11 接续
K11 用仅密文 Outbox 和本机密钥加密恢复胶囊补齐崩溃窗口;这里保留 K10 的历史边界。
K11 · TWO IOS TEXT LOOP
不是“能发一条”,而是任意一步被杀都能恢复
K11 将 K09 盲信箱、K10 Crypto Adapter 和独立 private_v1 本地事务拼成首个可执行双端闭环。Realtime 与 Push 只负责唤醒,权威事实始终来自 mailbox pull。
先本地耐久,再网络入队
消息与仅密文 Outbox 一起落盘;信箱接受后才推进 Olm。重启恢复同一密文,不重新加密或重复推进 Ratchet。
先保住可恢复正文,再提交 ACK
解密结果先封成本机密钥加密胶囊;本地消息提交后才推进 cursor 和签名 ACK。篡改时三者都不推进。
信箱接受后崩溃
重启幂等重试同一 envelope,服务端唯一信封仍为 1,本地 Outbox 最终清零。
三个写盘窗口全覆盖
恢复胶囊后、消息提交后、ACK 状态后分别杀进程,重启都只得到一条本地消息和一次 ACK。
K11 不等于用户可用
K12 已补齐本地保护,K16 已完成编译接线;当前生产开关和产品入口仍关闭,因此不得宣称 E2EE 已上线。签名 TestFlight 与真人试点已延期。
K12 · IOS LOCAL DATA PROTECTION
密文链安全,不代表设备落盘天然安全
K12 当刀把设备秘密、本地事务状态与搜索拆成三个失败关闭边界,并保持隔离;K16 已把它纳入 App 编译图,但没有开放产品入口,也不改变普通聊天。
秘密只从 Keychain 取句柄
设备材料使用 WhenUnlockedThisDeviceOnly;账号、设备与 generation 只形成哈希账户键,业务层拿不到原始秘密。
状态与身份绑定后再落盘
重放账本与 K11 状态使用不同 HKDF 域,AES-GCM AAD 绑定身份;篡改、错 key、错身份和旧明文全部拒绝。
认证后、只在内存中
用户在场认证签发短租约;搜索索引不进 SQLite、FTS、Spotlight 或日志,锁定立即清空。
诊断与通知不带正文
诊断只保留哈希标识和字节数;通知固定为“你有一条新私密消息”,不携带发送者、会话或内容。
K12 不等于已经上线
K16 只完成 App 编译接线;产品入口、TestFlight 和真实私密会话仍为 0,密文媒体格式已由 K13 接续。
K13 · PRIVATE MEDIA WIRE FORMAT
先在设备端变成密文,再跨越资源服务边界
K13 交付的是可运行的项目中立格式,不是概念图:真实实现位于 im-media-send-kit,iOS 与 Knowledge 保存同一份机器合同。K14 才把公开描述符和密文对象接入 reits-media/S3。
资源服务只看密文事实
只含不透明内容 ID、密文字节数、密文 SHA-256、块大小与块数;不含文件名、MIME、角色、明文摘要、key 或 nonce。
接收方材料不进入媒体服务
对象 key 与 nonce prefix 只放进已认证私聊消息;文件名、MIME、角色和明文完整性信息仍在独立认证密文内。
AES-256-GCM 分块处理
默认 1 MiB 明文块,nonce 由对象随机前缀和块序组成;完整文件不进入内存,空文件也产生认证块。
任何异常都不提交明文
篡改、截断、附加、错 key、错对象、描述符冲突和元数据认证失败全部删除临时输出。
K13 当时只冻结媒体格式
K13 没有接入 reits-media 和 S3;该缺口已由 K14 资源闭环接续,K16 只完成编译接线,运行入口仍关闭。
K14 · PRIVATE MEDIA CIPHERTEXT V1
密文直达 S3,EC2 不落业务资源字节
K14 把 K13 的密文格式接到真实资源边界:reits-media 只签发上传与下载票据、核对密文大小和摘要;设备到 S3 直接传输,资源节点不做代理转发,也不保存临时文件。
ec2_persistent_asset_bytes=false资源服务只处理公开密文事实
不透明内容 ID、密文字节数、密文 SHA-256、分块参数和幂等键;文件名、MIME、媒体角色、明文摘要、key 与 nonce 一律拒绝。
设备与 S3 直接交换密文
小对象单次 PUT;大对象分片续传并跳过已完成分片。Bearer 令牌只发给媒体控制面,不随预签名请求进入 S3。
服务端流式复核密文 SHA-256
完成提交前从对象存储流式读取并核对长度与摘要;不把完整对象写到 EC2 临时目录。
Range 密文回读
客户端按 K13 认证块范围请求,必须收到精确的 206 字节区间;任一摘要、长度或 tag 不一致都删除临时输出。
逻辑删除
对象锁定期内只撤销业务可见性和后续下载票据,不承诺立即物理删除;生命周期继续由 S3 治理。
K14 不等于产品已经开放
L14 已把五类密文媒体接到 shipping=false 后的真实收发入口,并补齐耐久任务账本、字节断点、短票据续签、当前分块后台传输与主动控制;用户入口仍关闭,整对象无人值守串行属于后续增强。
L10 ACCEPTED · UNIFIED RESOURCE LIFECYCLE
统一资源生命周期,不等于所有文件统一过期。
设备本地才是聊天资源的长期事实源;头像、MiniApp、业务文档、社交内容和构建产物各守自己的引用与合规周期。L10 已部署可回读合同,生产物理删除仍需独立授权。
ec2_persistent_asset_bytes=false| 资源类型 | 长期事实源 | 服务端保留 | 到期体验 |
|---|---|---|---|
私密聊天原件private_chat_original | 设备本地 | S3 密文临时中转 30 天 | 文件已过期,无法下载;可请对方重新发送或从完整设备迁移 |
普通聊天原件standard_chat_original | 设备本地 | S3 临时中转 30 天 | 保留消息气泡与元数据,显示过期状态,不无限重试 |
聊天派生资源chat_derivative | 可由本地原件重建 | 不得比原件活得更久 | 优先重建;原件也不存在时展示过期 |
用户与群头像profile_and_group_avatar | 当前资料引用 | 活动引用长期保留;失去引用后 30 天宽限 | 回退默认头像并重试资料元数据 |
贴纸与表情包sticker_and_emoji_package | 已发布版本 | 活动版本保留,至少留 2 个回滚版本 | 显示占位并刷新资源包 |
动态与 Storymoment_and_story_media | 内容发布记录 | Story 24 小时;动态按产品删除与墓碑 | 显示内容不可用,不冒充聊天重传 |
视频号与频道reel_and_channel_media | 已发布内容引用 | 跟随内容生命周期,删除后再回收 | 内容已移除或不可用 |
MiniApp 包miniapp_package | 不可变发布版本 | 活动引用受保护;无引用版本才可清理 | 回滚到可用版本或显示包不可用 |
业务资产business_asset | 业务记录引用 | 按合规策略;必须有 Owner 与引用证据才能删除 | 保留审计引用并显示业务记录不可用 |
设备迁移包migration_package | 来源设备本地数据库 | S3 密文中转 24 小时;导入成功立即删除 | 要求来源设备重新发起迁移 |
链接预览缓存link_preview_and_external_cache | 外部源站与消息元数据 | 有界缓存并定期重新验证 | 文本链接仍保留,预览允许消失 |
日志与构建产物logs_and_build_artifacts | 可观测性或发布系统 | 不进入 reits-media,使用独立留存与清理策略 | 不是终端用户资源 |
消息文字、发送者、时间与资源类型仍留在本地时间线;不出现空白气泡,不无限转圈,也不静默延长服务器留存。
- 本机有原件继续离线打开,不受 S3 到期影响。
- 本机无原件可请对方重新发送。
- 另一设备完整从完整设备发起加密迁移。
K15 · AUTHORIZED DEVICE FAN-OUT
完整设备名单不是客户端猜出来的
K15 只解决未来新消息:发送端自己的其他设备与接收方全部活跃设备都拿到独立密文;服务端重新计算名单并用一个事务接收整批,不允许部分送达。
会话双方完整快照
名单摘要绑定会话、账号、设备 ID、generation 与签名公钥;最高代 revoked 时不能退回旧 active。
逐设备独立信封
接收方所有设备,加上发送端其他设备;每个目标拥有不同 ciphertext、envelope ID、幂等键与签名。
名单变化就整批拒绝
im-core 重算摘要、验签全部信封、分配各设备序号;缺失、重复、撤销或写入失败时新增为 0。
发送端其他设备
手机发送后,自己的平板也从独立 mailbox 收到新消息;服务器不能复制手机那份密文代替端侧加密。
stale roster → 409
撤销使摘要变化,整批失败;仍活跃设备也不会提前看到半个批次。
Pull 继续检查 active
已撤销设备不能领取尚未消费的信封;但不虚假承诺远程擦除它已经落盘的明文。
K15 不等于产品已经开放
协调器已随 K16 Shipping 产品进入 App 编译图;运行入口、Feature Flag、TestFlight 和真实私聊会话仍为 0。
K16 · RUNTIME VALIDATION DEFERRED
工程已经完成,运行验证按需恢复
K16 工程代码已经合并 main,发布输入也通过 UTF-8 路径守卫。当前无真实用户,签名 TestFlight、生产白名单、真人体验和观察日统一延期;延期不等于验收通过,产品入口继续关闭。
通过 App 已有的 IMClientPluginBridge 聚合层链接唯一 Shipping 产品;真实 App 编译和供应链门禁均通过。
Run #82057 路径守卫已通过;自动打包机在需要真人窗口时再运行。
服务端约束鉴权 actor 与每一个消息参与者;当前无真实用户。
停止、回滚与隐私门禁已经保留在工程主线。
观测与停止合同保留;当前一人团队裁定延期。
以后在真实用户窗口中补离线、重启、重试与多设备场景。
K16 已修复后端路由和 snake_case 合同,并完成 5 个隔离模块 → 1 个 Shipping 产品。PR #133 完成 App 编译接线;PR #134 恢复 200 个真实 UTF-8 路径;发布编排 PR #27 修复隔离身份合同。自动打包机按需运行,生产门禁继续关闭。
contract sha256 · 1a8ce8b90ec8382938462489742484bf48184b3fdae28398a435453ef41562feCAPABILITY GAP
和 WhatsApp 级别的差距,逐项说清
“有加密代码”不等于“默认 E2EE”。差距集中在设备身份、逐消息密钥、盲投递、Push 和媒体边界。
| 能力 | 当前 | Private Chat v1 目标 | 刀次 |
|---|---|---|---|
| 每设备密码学身份 | K05 域模型与签名投影已合并;运行时接口尚未暴露 | 设备独立私钥,与账号授权链签名绑定 | K05 |
| 异步首次建链 | K09 已接入默认关闭的 reserve / commit API;产品门禁仍关闭 | signed prekey + one-time prekey + 独立 private_v1 会话 | K06–K09 |
| 逐消息密钥演进 | K10 已封装逐设备 Olm;K16 Shipping 产品已进入 App 编译图,运行门禁固定 false | Olm ratchet + 原子状态持久化 + 业务 Adapter | K03–K10 |
| 服务端盲投递 | K09 已接 SQL Store 与迁移角色;运行时开关默认关闭 | TTL / ACK / 幂等 / 乱序的密文 envelope 信箱 | K08–K09 |
| WebSocket / Push 隐私 | K09 已实现密文 WS 与仅含 schema/kind 的通用 Push;尚未开放给 App | WS 传 envelope,Push 只通用唤醒 | K09 |
| iOS 私密文本闭环 | 隔离双端闭环已通过;K10/K11/K12/K15/K16 已聚合并进入 App 编译图,但产品入口和 private_v1 会话仍为 0 | 离线、重启、重试后仍不丢不重不明文 | K10–K11 |
| 设备本地数据保护 | K12 已验证仅本机 Keychain、完整文件保护、加密状态与认证后内存搜索;编译接线 1/1,运行入口 0 | 私钥与本地明文只在受保护设备边界内可用 | K12 |
| 私聊密文媒体 | K14 已完成客户端分块 AEAD、直传 S3、断点续传、Range 回读与逻辑删除;编译接线 1/1,运行入口 0 | 客户端流式 AEAD,S3 只存密文 | K13–K14 |
| 新消息多设备 | K15 已完成最新活跃名单、逐设备独立密文、原子批次与撤销隔离;编译接线 1/1,运行入口 0 | 发送端逐已授权设备 fan-out | K15 |
| 封闭试点门禁 | K16 App 编译接线、后端边界、观测、停止与回滚已完成;签名 build、真人试点与观察延期 | 以后有真实用户时按需恢复 TestFlight 与观察 | K16 |
REPOSITORY OWNERSHIP
每个仓库不仅要知道做什么,还要知道绝对不做什么
最危险的不是少一个微服务,而是消息密钥、正文索引和媒体解密悄悄落到了错误的边界内。
matrix-x-chat-ios- 负责
- 协议库适配、设备私钥、逐设备加密、本地明文、安全 UI
- 不负责
- 缺 key 时把 Private Chat 当普通正文发出
im-core- 负责
- 公钥/预密钥目录、盲信箱、TTL、ACK、幂等、密文 WS 和唤醒
- 不负责
- 解密、索引正文、解析私聊 command、保存私钥
reits-auth- 负责
- 登录会话、可信设备 step-up、设备授权与撤销
- 不负责
- 保存消息密钥,或把 OAuth session 当 E2EE identity
reits-media- 负责
- 预签名、S3 密文对象、配额、checksum 和 lifecycle
- 不负责
- 解密私聊媒体、扫描原文件、保存媒体 key
im-media-send-kit- 负责
- 项目中立的流式加密、分片和 descriptor
- 不负责
- 知道具体聊天、用户和 CDN 域名
FOUNDATION EVIDENCE · K01—K16
旧 16 刀是安全基础证据,不冒充当前迁移进度。
K01–K16 证明协议、盲信箱、密文媒体与失败关闭能够实现;当前产品进度按开发规划中的 L01–L15计算。签名 App、真实账号、10 天观察与真人 TestFlight 已转为延期运行项,不再阻塞工程 15/15。
先说真话
业务收益停止假安全承诺,降低品牌与合规风险
工程验收正式 UI、文档和真实行为一致
证明可行
业务收益知道是否值得继续投入,不在生产上试算法
工程验收威胁模型、许可证结论与官方 Olm 状态机 POC
让服务端失明
业务收益数据泄漏半径从正文收缩为最小投递元数据
工程验收设备目录、预密钥、盲信箱和通用 Push
文本工程闭环
业务收益具备正式 App 装配前提,但不提前开放用户
工程验收两台 iOS 离线、重启、重试和本地数据保护
扩展媒体与多设备
业务收益从私密文本走向完整私聊体验
工程验收密文媒体和已授权设备新消息 fan-out
运行验证
业务收益真实用户出现后再恢复运行验证,不继续消耗当前一人团队
工程验收观测、停止与回滚代码保留;真人账号和 10 天观察延期
ACCEPTANCE · STOP CONDITIONS
安全项目的进度,必须能用“什么时候立刻停”来衡量
任意一条停止条件命中,试点都必须停止扩张;不允许为了“刀数进度”将安全问题改成非阻断。
任意 Private Chat 明文回退
服务端、日志、Push 或 S3 出现消息正文
被撤销设备仍取得新 envelope
升级导致已有私密消息永久不可解
协议库许可证或 TestFlight 分发权不明确
发现可批量解密或静默注入设备
Crash-free session 低于 99.5% 或投递成功率低于 99.9%
PR #133 已合并;复用既有桥接依赖,不修改受保护的 pbxproj,产品入口继续关闭。
只在发布编排仓对精确合并 SHA 归档、签名并上传 TestFlight。
双方账号都在组内;当前生产账号数为 0。
以后重新启用时仍按完整窗口执行,不回填历史数据。