跳至主要內容
進階

NIP-01 基本協議

深入了解 Nostr 的基本協議規範,事件格式、簽名驗證和客戶端-中繼器通訊。

18 分鐘

NIP-01 概述

NIP-01 定義了 Nostr 協議的基本元素:事件格式、簽名方案、 客戶端與中繼器之間的通訊協議,以及基本的訊息類型。 這是所有 Nostr 應用的基礎。

核心原則: Nostr 的設計極度簡單——每個用戶只有一對密鑰,所有內容都是簽名的事件。 中繼器只是轉發事件,不需要信任它們。

事件格式

每個事件都是一個 JSON 物件,包含以下欄位:

{
  "id": "事件 ID(內容的 SHA256 雜湊)",
  "pubkey": "發布者的公鑰(32 bytes hex)",
  "created_at": 1234567890,  // Unix 時間戳
  "kind": 1,                  // 事件類型
  "tags": [                   // 標籤陣列
    ["e", "引用的事件 ID"],
    ["p", "提及的公鑰"],
    ["t", "hashtag"]
  ],
  "content": "事件內容",
  "sig": "Schnorr 簽名(64 bytes hex)"
}

事件 ID 計算

事件 ID 是以下 JSON 序列化的 SHA256 雜湊:

// 序列化格式
[
  0,                    // 固定值
  <pubkey>,            // 發布者公鑰
  <created_at>,        // 時間戳
  <kind>,              // 事件類型
  <tags>,              // 標籤陣列
  <content>            // 內容字串
]

// 計算
id = SHA256(JSON.stringify(serialized))

常見事件類型 (Kind)

Kind 名稱 說明
0 Metadata 用戶個人資料(名稱、頭像、簡介)
1 Short Text Note 純文字貼文
2 Recommend Relay 推薦中繼器(已棄用)
3 Contacts 關注列表
4 Encrypted DM 加密私訊(NIP-04)
5 Event Deletion 刪除請求
7 Reaction 按讚、表情反應

客戶端-中繼器通訊

Nostr 使用 WebSocket 進行通訊,有三種訊息類型:

CLIENT → RELAY

  • EVENT 發布事件
  • REQ 訂閱查詢
  • CLOSE 關閉訂閱

RELAY → CLIENT

  • EVENT 返回事件
  • OK 確認收到
  • EOSE 訂閱結束
  • NOTICE 通知訊息

訊息格式

所有訊息都是 JSON 陣列,第一個元素是訊息類型

訂閱過濾器

REQ 訊息使用過濾器來查詢事件:

// 訂閱格式
["REQ", "<subscription_id>", <filter1>, <filter2>, ...]

// 過濾器選項
{
  "ids": ["<event_id>", ...],      // 特定事件 ID
  "authors": ["<pubkey>", ...],    // 特定作者
  "kinds": [0, 1, 3],               // 事件類型
  "#e": ["<event_id>", ...],       // 引用事件
  "#p": ["<pubkey>", ...],         // 提及用戶
  "#t": ["bitcoin", "nostr"],       // 標籤
  "since": 1234567890,              // 時間範圍起始
  "until": 1234567899,              // 時間範圍結束
  "limit": 100                      // 數量限制
}

實際範例

發布貼文

// 客戶端發送
["EVENT", {
  "id": "abc123...",
  "pubkey": "npub1...",
  "created_at": 1704067200,
  "kind": 1,
  "tags": [],
  "content": "Hello, Nostr!",
  "sig": "sig123..."
}]

// 中繼器回應
["OK", "abc123...", true, ""]

訂閱用戶貼文

// 客戶端請求
["REQ", "my-sub", {
  "authors": ["npub1..."],
  "kinds": [1],
  "limit": 50
}]

// 中繼器回應(多個事件)
["EVENT", "my-sub", {...event1...}]
["EVENT", "my-sub", {...event2...}]
["EOSE", "my-sub"]  // 歷史事件結束

// 新事件即時推送
["EVENT", "my-sub", {...new_event...}]

標籤系統

標籤是 Nostr 事件中的重要元素,用於關聯和索引:

標籤 格式 用途
e ["e", "<event_id>", "<relay>"] 引用/回覆事件
p ["p", "<pubkey>"] 提及用戶
t ["t", "hashtag"] 主題標籤
a ["a", "<kind>:<pubkey>:<d>"] 引用可替換事件

簽名驗證

Nostr 使用 Schnorr 簽名(secp256k1 曲線):

// 驗證步驟
1. 重新計算事件 ID
   computed_id = SHA256(serialize(event))

2. 驗證 ID 匹配
   assert(event.id === computed_id)

3. 驗證 Schnorr 簽名
   assert(schnorr.verify(event.sig, event.id, event.pubkey))

安全提示: 客戶端必須驗證每個收到的事件的簽名,不能信任中繼器。 這是 Nostr 去中心化信任模型的核心。

已複製連結
已複製到剪貼簿