一个 10 万人的群。有人发出一条管理信令:"移除用户 X"。
你的客户端凭什么决定要不要相信这条信令?
大多数 messenger 的答案是查一张表 —— 服务器的、本地的、或者两边的。WhatsApp 的服务器查群成员表。Telegram bot framework 问服务器"这个人是管理员吗"。Discord 本地缓存一份角色表,相信缓存。归根到底就是"服务器记得 + 客户端缓存服务器说过的"。
BlindPost 的答案不一样。我们的服务器不知道任何群里谁是管理员,因为我们没有"角色"这张表。你的客户端也不查自己本地数据库去验证。信令自己带着证明走。任何发出管理动作的人,都附带一条密码学链,任何持有这个群公开标识符的人都可以端到端验证它 —— 不用问任何其他来源。
下面用标准密码学的层面,讲清楚这条链怎么搭。
三层角色
BlindPost 里每条群操作都由这三层之一签发:
- 群主(Owner) —— 群的创建者。群的永久标识符本身就是一对 Ed25519 密钥的公钥那半,群主就是持有私钥那半的那个人。密码学上,群主有且仅有一个 —— 就是握住那把密钥的人。
- 管理员(Admin) —— 任何被群主授权过的人,授权方式是群主对管理员的公钥签了一次名。
- 成员(Member) —— 任何持有群内容加密密钥的人,这把密钥通过端到端加密的邀请信令分发。
整个角色模型就这三层。没有表、没有名单、没有任何数据库里的"角色"字段。每一层的权威建立方式都是同一个范式:证明自己持有某把私钥。
群主信令怎么自证
群主发出一个动作(踢人、改设置、轮换密钥)的时候,把动作 payload 用群的 Ed25519 身份私钥签名。
接收方验证就一步:
- 取出群的公开标识符 —— 也就是这同一对密钥的公钥半。这个公钥你加群的时候就已经有了。
- 用这个公钥验信令上的签名。
签名能过 → 这条动作就出自持有群私钥的人 —— 按定义就是群主。没有服务器往返。没有本地数据库查询。 验证方所需要的一切,要么在信令里(签名 + payload),要么在它自己加入群时就已经有的公开标识符里。
管理员信令怎么自证:两步签名链
管理员这层更有意思,因为管理员是被授权出来的。管理员有自己的一对密钥(我们叫它 admin keypair),群主在某个时刻"宣布过这把 admin 公钥被授权"。
这个"宣布"本身就是一次签名:群主用群身份私钥,对 admin 的公钥签了一次。后来 admin 真的发动作的时候,用 admin 私钥对 payload 签名。接收方收到的是:信令 + admin 对它的签名 + admin 的公钥(连同群主对这把 admin 公钥的签名)一起打包。
验证两步:
- 验证 admin 对 payload 的签名,用 admin 公钥。
- 验证群主对 admin 公钥的授权签名,用群的公开标识符。
两步都过 → 这条动作出自被群主授权过的人。完事。还是没有数据库。还是没有服务器。
这其实就是 TLS 证书链的同款模式 —— 叶子证书 + 根证书,叶子由根签发,根公开可信 —— 只是搬到了群治理上。
成员信令怎么自证:它存在,就证明了自己
成员级信令的证明最优雅:如果你成功解开了这条信令,那发送方就是个成员。 任何没拿到群加密密钥的人,根本造不出一段能在这把密钥下正确解密的密文。"成员身份"塌缩成"持有密钥"。
对于需要明确归属的动作(投票里谁投了什么、消息上谁加了哪个 reaction),信令里额外带上成员的身份公钥和签名,接收方做一次验证。但对于不需要明确归属的动作,这一步都省了 —— 能解密本身就是证明。
"踢人"实际上是密钥轮换
整套架构的题眼:当你从 BlindPost 群里移除一个管理员或成员时,没有任何"成员表"被改动 —— 因为根本没有那张表。实际发生的是:群的内容加密密钥被轮换,被踢的人不在新密钥的分发名单里。
他的旧密钥还能解他之前已经收到的消息。但解不了轮换之后发的任何新消息。密码学边界移动,社会结构跟着对齐。撤销管理员也是同款:那条旧的授权签名在数学上永远有效,只是它不再 matter —— 那个被撤的 admin 没办法再参与加密 channel 了。
你不需要相信什么
要在 BlindPost 群里评估一条管理信令,你不需要相信:
- 我们的服务器。它没有任何角色信息可以给你 —— 对的或错的都没有。
- 你自己客户端的本地状态。整条验证路径上不查任何成员表;一切都在信令里。
- 任何第三方。没有交叉引用、没有密钥托管、没有证书颁发机构。
你只需要相信数学,以及你已经在的那个群的公开标识符(既然你在群里,你显然有这个标识符)。剩下的事,信令自己带着证明走。
我们的标语是"服务器是盲的"。这是补齐的另外一半:客户端也不需要全知全能。密码学授权通过网络传播,没有人需要去查任何表 —— 任何地方都不查。
BlindPost