Nostr 的实际工作原理:无术语的协议解析
在底层,Nostr 是一份 200 行的规范。事件、签名、relay、订阅。每个运动部件均配有具体示例。
大多数关于 Nostr 的解释止步于"它是一个去中心化的社交协议",而将最有趣的部分略去不提。有趣的部分在于,整个协议只需一份简短的文档就能容纳。没有奇技淫巧,没有隐藏的复杂性。只有几个相互协作的基本原语。
本指南按照你实际使用 Nostr 时遇到的顺序,逐一介绍这些原语:事件如何构建、如何签名、如何到达 relay、客户端如何订阅,以及当你点赞一篇帖子、收到回复或收到 zap 时的完整流程。无区块链类比,无宏大叙事,只有机制本身。
TL;DR. Nostr 是基于 WebSocket 的发布/订阅协议,配有密码学签名。客户端将已签名的 JSON 对象(事件)发布到 relay(小型服务器),其他客户端则向 relay 发送带有过滤条件的订阅请求,以获取所需事件。签名防止伪造;多个 relay 避免单点故障。这就是整个协议;其余的一切不过是针对不同内容类型的格式约定。
准备好后, 领取你的 @nostr.blog 地址
基本构建块:事件
Nostr 上的一切都是事件。一篇帖子是事件,一个点赞是事件,一次个人资料更新是事件,一条私信是事件,一笔 zap 收据也是事件。
事件是一个具有以下固定结构的 JSON 对象:
{
"id": "abc123...",
"pubkey": "0a4f7b1a3d9a1529a3080c3ae5ee553e0af0a01d86d01677c0bb270592923f88",
"created_at": 1776329035,
"kind": 1,
"tags": [
["t", "nostr"],
["p", "3bf0c63f..."]
],
"content": "hello nostr",
"sig": "def456..."
}
六个字段各司其职。id 是事件自身内容的哈希值,用于唯一标识该事件。pubkey 是作者(一个 64 字符的十六进制公钥)。created_at 是 Unix 时间戳。kind 是描述事件类型的整数(详见下文)。tags 是结构化注释列表,例如话题标签(t)、提及(p 表示 pubkey,e 表示事件)等数十种类型。content 是自由格式的载荷,通常为文本。
sig 是 Schnorr 签名,由作者使用私钥对 id 中的哈希值进行签名。这个字段是防伪的关键:任何人都可以计算哈希值,但只有私钥持有者才能生成有效签名。
"kind" 是什么
kind 字段告诉客户端如何解释该事件,这个数字本身就代表完整的语义类型。
当前活跃使用的几种 kind:
| Kind | 含义 |
|---|---|
| 0 | 个人资料元数据(名称、头像、简介) |
| 1 | 短文本笔记(Nostr 中相当于推文) |
| 3 | 联系人列表(你关注的人) |
| 4 | 私信(旧版,正被 1059 取代) |
| 5 | 删除请求 |
| 6 | 转发短文本笔记 |
| 7 | 反应(点赞、踩、表情符号) |
| 9734 | Zap 请求 |
| 9735 | Zap 收据 |
| 30023 | 长篇文章 |
| 1059 | 礼品包装私信(NIP-44/NIP-17) |
新的 kind 通过 NIP(Nostr 实现可能性) 提案和标准化流程提出。任何人都可以提案。被广泛采用的 kind 会成为协议的事实组成部分;未被采用的则只是小众用途,不会破坏任何已有功能。
事件如何被发布
当你在 Nostr 客户端点击"发布"时,以下流程依次执行:
- 客户端组装 JSON。 填入
pubkey、created_at、kind、tags、content。 - 客户端计算 id。 对这些字段的规范序列化结果执行 SHA-256 哈希。这是签名所覆盖的哈希值。
- 客户端用私钥对 id 签名。 使用
secp256k1曲线(与比特币相同)进行 Schnorr 签名。64 字节的签名成为sig字段。 - 客户端向每个已配置的 relay 建立 WebSocket 连接。 若已有活跃连接则复用。
- 客户端以消息形式发送事件。 线上格式为 JSON 数组:
["EVENT", {...event...}]。 - 每个 relay 验证签名。 若签名无法通过与声明 pubkey 的验证,则拒绝该事件;否则接受并存储。
- 每个 relay 将事件推送给订阅者。 任何持有匹配该事件过滤条件的活跃订阅的客户端都会实时收到该事件。
根据 relay 位置不同,整个往返过程耗时 50 至 300 毫秒。如果某个 relay 响应缓慢或下线,其他 relay 仍会正常发布该事件。只要有一个 relay 接受,事件即存在于网络之上。
客户端如何获取帖子
读取是发布的镜像操作。
你的客户端向一组 relay 建立 WebSocket 连接。对每个 relay,它发送一条订阅消息:
["REQ", "sub_id_1", { "authors": ["pubkey1", "pubkey2", ...], "kinds": [1, 6], "limit": 50 }]
这会请求 relay 返回列表中作者的最多 50 条 kind 1(短文本笔记)或 kind 6(转发)事件。relay 的处理流程如下:
- 查询本地数据库中匹配的事件,以
EVENT消息的形式回传给客户端(默认按从旧到新排序,不超过 limit 上限)。 - 发送
EOSE(已存储事件结束)消息,通知客户端历史数据传输完成。 - 保持订阅打开。 任何后续匹配该过滤条件的新事件(由他人发布)都会实时推送给客户端。
这就是你的信息流实现实时更新的方式。你不是在轮询;relay 在向你推流。
你的客户端在所有已配置的 relay 上并行执行这一操作。各 relay 响应的并集构成你的时间线。来自不同 relay 的重复事件通过 id 去重。
签名如何真正防止伪造
这是大多数解释一笔带过的部分。
当客户端收到一个事件时,它会对规范序列化结果重新计算哈希(与发布者的方式相同),然后执行 Schnorr 验证:给定 pubkey、id 和 sig,签名在密码学上是否成立?
若成立,则事件是真实的。该事件的作者是在签名时刻持有该 pubkey 的人。每个客户端对每个事件都执行此检查。一个转发了签名有误的伪造事件的 relay,只会让每个见到它的客户端静默丢弃该事件。
这很重要,因为这意味着 relay 是不受信任的。恶意 relay 无法替你发言。它可以拒绝转发你的帖子,可以将他人的(合法)帖子注入你的信息流,但它无法在没有你私钥的情况下生成一条由你签名的有效帖子,也无法在不破坏签名的前提下修改你已有的帖子。
这一特性的代价恰好是每个事件一次 Schnorr 验证,速度足够快,即便是移动端客户端也能以每秒数万次事件的速度处理。
Relay 实际上做什么
Relay 是一个简单、快速的管道,只有三项职责:
- 接受事件并验证签名。 拒绝任何无法通过验证或违反策略检查(垃圾过滤、大小限制、屏蔽的 pubkey)的事件。
- 存储事件。 通常存入以
id、pubkey、kind和标签值为索引的 SQLite 或 PostgreSQL 数据库。 - 处理订阅。 将传入的
REQ过滤条件与数据库(历史事件)及实时事件进行匹配。
仅此而已。Relay 不做排名、不做推荐、不做策划、不做变现、不展示广告、不运行算法,也不做任何平台会做的事。它只是转发已签名的字节。
缺少这些额外职责,正是 relay 可以非常小巧的原因。一台每月 5 美元的 VPS 就能运行一个服务数百名活跃用户的 relay。同样的功能在 Twitter 规模下需要数十亿美元,因为 Twitter 还要做所有其他的事。
Relay 的策略各不相同。有些是无许可的,转发任何已签名的事件;有些需要付费("付费 relay"模式);有些限制特定社区使用(某公司员工、某 Discord 服务器成员);还有一些在垃圾过滤上非常积极。你可以选择使用哪些 relay;你的选择会影响你能看到哪些帖子,以及哪些帖子能触达你的关注者。
完整示例:有人点赞了你的帖子
综合以上内容,以下是 Alice 点赞 Bob 帖子时端到端发生的完整流程。
- Bob 发布。 Bob 的客户端构建一个内容为"hello world"的 kind:1 事件,签名后发送到 Bob 配置的五个 relay。每个 relay 接受并存储。
- Alice 订阅。 Alice 的客户端在其中两个 relay 上持有一个活跃订阅,过滤条件的
authors中包含 Bob 的 pubkey。relay 将 Bob 的事件推送下来。Alice 的客户端在她的时间线中展示该帖子。 - Alice 点赞。 Alice 的客户端构建一个 kind:7 事件,内容为"+"(Nostr 的点赞惯例),标签中关联了被点赞的帖子(
["e", "bob_post_id"])和作者(["p", "bob_pubkey"])。签名后发布到 Alice 配置的五个 relay。 - 反应传播。 任何持有匹配过滤条件
{ "#e": ["bob_post_id"], "kinds": [7] }的活跃订阅的 relay(这正是 Bob 的客户端用来监听自己帖子反应的订阅),都会将该反应推送给 Bob。Bob 的客户端汇总点赞数并在帖子下方显示计数。
注意,以下事情并没有发生:没有中心化的"点赞按钮"服务被调用,没有后端决定点赞是否被计入。点赞只是一个已签名的事件,在与帖子本身相同的频道上广播。
Nostr 明确不做什么
核心协议有意省略了以下五件事,因为它们属于客户端或 relay 层面,而不属于共享的线上格式。
- 身份验证。 Nostr 只能证明"这个 pubkey 签署了这篇帖子"。该 pubkey 是否属于某个特定的人,是另一个问题,由 NIP-05 和链下上下文来回答。
- 内容审核。 协议不决定什么内容可见。客户端过滤、relay 过滤、用户过滤,每一层独立运作。
- 搜索。 不存在全局搜索端点。部分 relay 支持对其本地事件池进行文本搜索;协议层面不保证任何 relay 能找到任意帖子。
- 算法排名。 协议中没有"为你推荐"信息流。排名若有的话,发生在客户端层面。
- 账号恢复。 没有邮件重置、没有手机重置、没有中心化争议处理系统。私钥丢失,身份即丢失。这是一种权衡,不是缺陷。
这些缺失正是协议保持精简的原因。同时也正是在此之上构建精致用户体验比在中心化平台上更难的真实代价。
这种设计为何能奏效
这一设计依赖一个简单的特性:签名验证代价低廉,没有私钥的伪造不可能实现,relay 可以自由替换。
这三个事实相互叠加。低廉的验证意味着每个客户端都能检查每个事件。不可能的伪造意味着 relay 不需要被信任。自由的替换意味着没有任何单一 relay 对任何人拥有控制权。
综合起来,你得到的是一个平台层可互换、身份层归用户所有的社交网络。这才是"去中心化"在实践中的真正含义,而非营销话语中通常使用该词的方式。
如果你想从用户视角了解完整流程(一对密钥、一个 NIP-05 身份、一份 relay 列表、一个钱包,准备好发帖),nostr.blog 的注册流程将这些步骤整合到了一个页面中。本文所描述的机制,正是在那个流程底层实际运行的内容。
常见问题
Nostr 是区块链吗?
Nostr 如何防止他人伪造我的帖子?
如果某个 relay 下线了会怎样?
客户端如何找到我的帖子?
Relay 能看到我的私信吗?
继续阅读
什么是 Nostr?2026 年简明英文指南
Nostr 是一个用于社交媒体和身份的简单、开放协议。没有公司运营它,没有任何账户可以被除了你之外的任何人删除。简明英文。
阅读约 10 分钟新手上路如何使用Nostr:初学者分步指南
打开应用,获取一对密钥,关注一些人,发布内容。这就是2026年Nostr的入门过程,包括没人会警告你的细节。
阅读约 14 分钟身份与 NIP-05什么是 NIP-05?Nostr 地址解析
NIP-05 是你在 Nostr 上使用的电子邮件形式的标识符:alice@nostr.blog。它的实际作用、不能做什么,以及如何获得一个。
阅读约 11 分钟进阶与技术Nostr DM真的私密吗?诚实的答案
Nostr DM使用加密,但隐私模型存在漏洞。NIP-04、NIP-44和NIP-17礼物包装保护了什么,以及何时改用Signal。
阅读约 11 分钟进阶与技术如何在 2026 年运行你自己的 Nostr 中继
在便宜 VPS 上运行 Nostr 中继的实用指南。包括软件选择、配置方法、成本估算以及为什么你可能想要运行一个。
阅读约 12 分钟