NIP-95: Protocolo Híbrido Relay-P2P via WebRTC

OK3E

npub1jxl2tnvnv9gycsy64aze295c3a529lx5sfmzlktf5lxuw805g5wqew0z0n

hex

108f443daba652bfc133accaba4cd183b830f98a29f27b0a595f6daad738f5de

nevent

nevent1qqsppr6y8k46v54lcye6ej46fngc8wpslx9znunmpfv47md26uu0thsprpmhxue69uhhyetvv9ujuem4d36kwatvw5hx6mm9qgsfr049ekfkz5zvgzd273v4z6vg769zln2gya30m9560nw8rh6y28qmjeapu

naddr

naddr1qqxxummnw3ez6mnfwqknjdgprpmhxue69uhhyetvv9ujuem4d36kwatvw5hx6mm9qgsfr049ekfkz5zvgzd273v4z6vg769zln2gya30m9560nw8rh6y28qrqsqqqa28ct4vp5

Kind-30023 (Article)

2026-06-04T21:08:29Z

1. Resumo Executivo

A NIP-95 estende o protocolo Nostr (NIP-01) para permitir uma arquitetura de distribuição de eventos híbrida. O Relay deixa de ser a única fonte de verdade e entrega, passando a atuar também como um Seed Node e Signaling Server. Clientes estáveis tornam-se Super Peers, servindo eventos recentes via WebRTC Data Channels para outros peers, reduzindo drasticamente o consumo de banda e a carga de processamento do relay central.


2. Taxonomia de Nós (Papéis)

| Papel | Descrição | Requisitos Técnicos | | :--- | :--- | :--- | | Relay Seed | Nó de autoridade e coordenação. Armazena histórico completo. | Suporte a WebSocket + Lógica de Signaling + Indexação de Cache de Peers. | | Super Peer | Cliente estável que atua como servidor P2P temporário. | Conexão >30min, Uptime alto, Cache Local (IndexedDB/LevelDB). | | Casual Peer | Cliente padrão (mobile ou instável). Consumidor prioritário. | Suporte a WebRTC e fallback para WebSocket. |


3. Mensagens do Protocolo (Client <-> Relay)

As mensagens seguem o formato JSON padrão do Nostr: ["COMANDO", <payload>].

3.1 Registro e Gerenciamento de Peer

PEER_REGISTER (Client -> Relay)

Anuncia a intenção do cliente de participar da rede P2P.

[
  "PEER_REGISTER",
  {
    "bandwidth": 10,      // Mbps (opcional)
    "storage": 500,       // MB disponíveis para cache (opcional)
    "publicKey": "hex",   // Identidade para reputação/pagamentos
    "lightningAddress": "[email protected]" // Incentivos futuros
  }
]

PEER_REGISTERED (Relay -> Client)

Confirmação de registro e atribuição de ID de sessão.

[
  "PEER_REGISTERED",
  {
    "peer_id": "uuid-v4",
    "heartbeat_interval": 30000,
    "status": "registered"
  }
]

3.2 Sincronização de Cache

PEER_CACHE_HAVE (Client -> Relay)

Informa ao relay quais eventos o cliente possui em seu cache local para que o relay possa rotear requisições.

[
  "PEER_CACHE_HAVE",
  {
    "events": [
      { "id": "hex", "pubkey": "hex", "kind": 1, "created_at": 162... },
      ...
    ]
  }
]

3.3 Descoberta e Signaling (Smart Routing)

PEER_OFFER (Relay -> Client)

Enviado pelo relay quando um cliente faz um REQ e o relay identifica que Super Peers possuem os dados.

[
  "PEER_OFFER",
  {
    "subscription": "sub_id_123",
    "offers": {
       "event_id_abc": ["peer_id_1", "peer_id_2"],
       "event_id_def": ["peer_id_3"]
    },
    "source": "smart_routing"
  }
]

PEER_SIGNAL (Client -> Relay -> Client)

Encapsula o handshake WebRTC (SDP/ICE Candidates). O Relay apenas repassa.

[
  "PEER_SIGNAL",
  {
    "target_peer": "uuid-do-outro-peer",
    "signal_data": { "type": "offer/answer", "sdp": "..." } // ou ice candidate
  }
]

4. Comunicação P2P (Peer <-> Peer via WebRTC)

Uma vez aberto o WebRTC Data Channel, os peers trocam mensagens binárias ou JSON diretamente.

4.1 Requisição de Evento (P2P_REQUEST)

{
  "type": "P2P_REQUEST",
  "event_id": "hex-id-do-evento"
}

4.2 Entrega de Evento (P2P_EVENTS)

{
  "type": "P2P_EVENTS",
  "event": {
    "id": "...",
    "pubkey": "...",
    "sig": "...",
    "content": "...",
    ...
  }
}

5. Algoritmos e Lógica de Implementação (LLM Guide)

5.1 O Algoritmo de "Smart Routing" (No Relay)

Ao receber uma mensagem ["REQ", sub_id, filter]:

  1. Processamento Padrão: O relay deve buscar no banco de dados local e enviar eventos via WebSocket (compatibilidade NIP-01).
  2. Interseção de Cache: O relay consulta seu CacheTracker (um mapa em memória de event_id -> Set<peer_id>).
  3. Seleção de Peers: Se o filtro do REQ bater com eventos indexados no CacheTracker:
    • Selecione até 3 Super Peers online para cada evento.
    • Envie PEER_OFFER ao cliente solicitante.

5.2 O Processo de Promoção (Super Peer)

O Relay deve manter um loop de monitoramento (ex: a cada 1 min):

  • Se peer.uptime > 30min AND peer.reputation > threshold AND peer.cache_size > 0:
    • Envie ["PEER_PROMOTED", { "peer_id": "..." }].
  • Se o peer desconectar ou falhar em responder heartbeats:
    • Remova-o de todos os índices de CacheTracker.

5.3 O Handshake WebRTC (Signaling)

  1. Peer B (Requester) recebe PEER_OFFER contendo Peer A.
  2. Peer B gera um SDP Offer e envia ao Relay: ["PEER_SIGNAL", { target: "Peer A", signal: offer }].
  3. Relay localiza a conexão WebSocket de Peer A e repassa: ["PEER_SIGNAL_RELAY", { from: "Peer B", signal: offer }].
  4. Peer A gera um SDP Answer e envia ao Relay: ["PEER_SIGNAL", { target: "Peer B", signal: answer }].
  5. Relay repassa ao Peer B.
  6. Conexão P2P estabelecida via STUN/TURN.

6. Segurança e Integridade

  1. Assinaturas Schnorr: Clientes OBRIGATORIAMENTE devem validar a assinatura (sig) de cada evento recebido via P2P usando a biblioteca noble-curves ou similar. Se o ID do evento ou a assinatura forem inválidos, o peer remetente deve ser desconectado e reportado.
  2. Reputação de Peer:
    • O Relay deve manter um score de reputação no Redis/DB.
    • +1 para cada evento validado e entregue (reportado via PEER_STATS).
    • -100 (banimento) para envio de assinaturas falsas.
    • Decay temporal: Reputação diminui se o peer ficar offline.
  3. Privacidade: O uso de WebRTC expõe o endereço IP entre os peers. Clientes devem solicitar consentimento do usuário antes de ativar o modo P2P ("Enable P2P Acceleration").

7. Extensão NIP-11 (Relay Information)

Relays compatíveis devem anunciar os limites do protocolo:

{
  "supported_nips": [1, 11, 95],
  "limitation": {
    "p2p_enabled": true,
    "p2p_max_connections_per_peer": 10,
    "p2p_heartbeat_ms": 30000
  }
}

8. Pseudocódigo para Implementação em LLM

Handler de Mensagem (Servidor)

function handleMessage(client, message) {
  const [type, payload] = message;
  switch(type) {
    case "PEER_REGISTER":
      return registerPeer(client, payload);
    case "PEER_CACHE_HAVE":
      return updateCacheTracker(client.id, payload.events);
    case "PEER_SIGNAL":
      const target = getClientById(payload.target_peer);
      if (target) {
        send(target, ["PEER_SIGNAL_RELAY", { from: client.id, signal: payload.signal_data }]);
      }
      break;
    case "REQ":
      handleStandardNip01(client, payload);
      triggerSmartRouting(client, payload); // NIP-95 logic
      break;
  }
}

Handler de Recebimento P2P (Cliente)

peer.on('data', data => {
  const msg = JSON.parse(data);
  if (msg.type === 'P2P_EVENTS') {
    if (nostr.verifySignature(msg.event)) {
      displayEvent(msg.event);
      localCache.save(msg.event);
    } else {
      reportMaliciousPeer(msg.peer_id);
    }
  }
});

9. Fluxograma de Decisão (LLM Reasoning)

  1. Input: Filtro Nostr (ex: { "kinds": [1], "limit": 10 }).
  2. Relay Query: Busca no DB local (Fast).
  3. P2P Query: Verifica se algum Super Peer enviou PEER_CACHE_HAVE recentemente com kind: 1.
  4. Action: Envia resultados do DB via WebSocket + PEER_OFFER para conectar aos Super Peers que têm mais eventos do mesmo tipo, visando futuras atualizações.
  5. Result: O cliente recebe os primeiros 10 eventos via WebSocket (baixa latência) e estabelece P2P para o fluxo contínuo (sustentabilidade).

原始 JSON

{
  "kind": 30023,
  "id": "108f443daba652bfc133accaba4cd183b830f98a29f27b0a595f6daad738f5de",
  "pubkey": "91bea5cd9361504c409aaf459516988f68a2fcd482762fd969a7cdc71df4451c",
  "created_at": 1780607504,
  "tags": [
    [
      "d",
      "nostr-nip-95"
    ],
    [
      "alt",
      "Blog post: NIP-95: Protocolo Híbrido Relay-P2P via WebRTC"
    ],
    [
      "title",
      "NIP-95: Protocolo Híbrido Relay-P2P via WebRTC"
    ],
    [
      "summary",
      "Esta é uma especificação técnica exaustiva para a **NIP-95 (Hybrid Peer-to-Peer Relay Protocol)**. Ela foi desenhada para ser \"LLM-ready\", fornecendo definições de mensagens, fluxos lógicos, esquemas de dados e regras de estado que permitem a um modelo de IA gerar código funcional para clientes ou servidores Nostr."
    ],
    [
      "published_at",
      "1780607309"
    ],
    [
      "t",
      "nostr"
    ],
    [
      "t",
      "nip95"
    ],
    [
      "t",
      "nip"
    ],
    [
      "t",
      "webrtc"
    ],
    [
      "t",
      "relay"
    ],
    [
      "t",
      "relay-p2p"
    ],
    [
      "t",
      "p2p"
    ],
    [
      "r",
      "https://updatecachetracker(client.id/"
    ],
    [
      "r",
      "https://payload.signal/"
    ],
    [
      "r",
      "https://client.id/"
    ],
    [
      "r",
      "https://`peer.reputation/"
    ],
    [
      "r",
      "https://`peer.uptime/"
    ],
    [
      "r",
      "https://`peer.cache/"
    ],
    [
      "r",
      "https://peer.on/"
    ],
    [
      "r",
      "https://json.parse/"
    ],
    [
      "r",
      "https://displayevent(msg.event/"
    ],
    [
      "r",
      "https://getclientbyid(payload.target/"
    ],
    [
      "r",
      "https://reportmaliciouspeer(msg.peer/"
    ],
    [
      "r",
      "https://msg.type/"
    ],
    [
      "r",
      "https://msg.event/"
    ],
    [
      "r",
      "https://localcache.save/"
    ],
    [
      "r",
      "https://payload.events/"
    ],
    [
      "r",
      "https://nostr.verifysignature/"
    ],
    [
      "r",
      "https://\"[email protected]/"
    ],
    [
      "client",
      "Amethyst"
    ]
  ],
  "content": "## 1. Resumo Executivo\nA NIP-95 estende o protocolo Nostr (NIP-01) para permitir uma arquitetura de distribuição de eventos híbrida. O Relay deixa de ser a única fonte de verdade e entrega, passando a atuar também como um **Seed Node** e **Signaling Server**. Clientes estáveis tornam-se **Super Peers**, servindo eventos recentes via WebRTC Data Channels para outros peers, reduzindo drasticamente o consumo de banda e a carga de processamento do relay central.\n\n---\n\n## 2. Taxonomia de Nós (Papéis)\n\n| Papel | Descrição | Requisitos Técnicos |\n| :--- | :--- | :--- |\n| **Relay Seed** | Nó de autoridade e coordenação. Armazena histórico completo. | Suporte a WebSocket + Lógica de Signaling + Indexação de Cache de Peers. |\n| **Super Peer** | Cliente estável que atua como servidor P2P temporário. | Conexão \u003e30min, Uptime alto, Cache Local (IndexedDB/LevelDB). |\n| **Casual Peer** | Cliente padrão (mobile ou instável). Consumidor prioritário. | Suporte a WebRTC e fallback para WebSocket. |\n\n---\n\n## 3. Mensagens do Protocolo (Client \u003c-\u003e Relay)\n\nAs mensagens seguem o formato JSON padrão do Nostr: `[\"COMANDO\", \u003cpayload\u003e]`.\n\n### 3.1 Registro e Gerenciamento de Peer\n\n#### `PEER_REGISTER` (Client -\u003e Relay)\nAnuncia a intenção do cliente de participar da rede P2P.\n```json\n[\n  \"PEER_REGISTER\",\n  {\n    \"bandwidth\": 10,      // Mbps (opcional)\n    \"storage\": 500,       // MB disponíveis para cache (opcional)\n    \"publicKey\": \"hex\",   // Identidade para reputação/pagamentos\n    \"lightningAddress\": \"[email protected]\" // Incentivos futuros\n  }\n]\n```\n\n#### `PEER_REGISTERED` (Relay -\u003e Client)\nConfirmação de registro e atribuição de ID de sessão.\n```json\n[\n  \"PEER_REGISTERED\",\n  {\n    \"peer_id\": \"uuid-v4\",\n    \"heartbeat_interval\": 30000,\n    \"status\": \"registered\"\n  }\n]\n```\n\n### 3.2 Sincronização de Cache\n\n#### `PEER_CACHE_HAVE` (Client -\u003e Relay)\nInforma ao relay quais eventos o cliente possui em seu cache local para que o relay possa rotear requisições.\n```json\n[\n  \"PEER_CACHE_HAVE\",\n  {\n    \"events\": [\n      { \"id\": \"hex\", \"pubkey\": \"hex\", \"kind\": 1, \"created_at\": 162... },\n      ...\n    ]\n  }\n]\n```\n\n### 3.3 Descoberta e Signaling (Smart Routing)\n\n#### `PEER_OFFER` (Relay -\u003e Client)\nEnviado pelo relay quando um cliente faz um `REQ` e o relay identifica que Super Peers possuem os dados.\n```json\n[\n  \"PEER_OFFER\",\n  {\n    \"subscription\": \"sub_id_123\",\n    \"offers\": {\n       \"event_id_abc\": [\"peer_id_1\", \"peer_id_2\"],\n       \"event_id_def\": [\"peer_id_3\"]\n    },\n    \"source\": \"smart_routing\"\n  }\n]\n```\n\n#### `PEER_SIGNAL` (Client -\u003e Relay -\u003e Client)\nEncapsula o handshake WebRTC (SDP/ICE Candidates). O Relay apenas repassa.\n```json\n[\n  \"PEER_SIGNAL\",\n  {\n    \"target_peer\": \"uuid-do-outro-peer\",\n    \"signal_data\": { \"type\": \"offer/answer\", \"sdp\": \"...\" } // ou ice candidate\n  }\n]\n```\n\n---\n\n## 4. Comunicação P2P (Peer \u003c-\u003e Peer via WebRTC)\n\nUma vez aberto o **WebRTC Data Channel**, os peers trocam mensagens binárias ou JSON diretamente.\n\n### 4.1 Requisição de Evento (`P2P_REQUEST`)\n```json\n{\n  \"type\": \"P2P_REQUEST\",\n  \"event_id\": \"hex-id-do-evento\"\n}\n```\n\n### 4.2 Entrega de Evento (`P2P_EVENTS`)\n```json\n{\n  \"type\": \"P2P_EVENTS\",\n  \"event\": {\n    \"id\": \"...\",\n    \"pubkey\": \"...\",\n    \"sig\": \"...\",\n    \"content\": \"...\",\n    ...\n  }\n}\n```\n\n---\n\n## 5. Algoritmos e Lógica de Implementação (LLM Guide)\n\n### 5.1 O Algoritmo de \"Smart Routing\" (No Relay)\nAo receber uma mensagem `[\"REQ\", sub_id, filter]`:\n1. **Processamento Padrão:** O relay deve buscar no banco de dados local e enviar eventos via WebSocket (compatibilidade NIP-01).\n2. **Interseção de Cache:** O relay consulta seu `CacheTracker` (um mapa em memória de `event_id -\u003e Set\u003cpeer_id\u003e`).\n3. **Seleção de Peers:** Se o filtro do `REQ` bater com eventos indexados no `CacheTracker`:\n   - Selecione até 3 Super Peers online para cada evento.\n   - Envie `PEER_OFFER` ao cliente solicitante.\n\n### 5.2 O Processo de Promoção (Super Peer)\nO Relay deve manter um loop de monitoramento (ex: a cada 1 min):\n- Se `peer.uptime \u003e 30min` AND `peer.reputation \u003e threshold` AND `peer.cache_size \u003e 0`:\n  - Envie `[\"PEER_PROMOTED\", { \"peer_id\": \"...\" }]`.\n- Se o peer desconectar ou falhar em responder heartbeats:\n  - Remova-o de todos os índices de `CacheTracker`.\n\n### 5.3 O Handshake WebRTC (Signaling)\n1. **Peer B (Requester)** recebe `PEER_OFFER` contendo `Peer A`.\n2. **Peer B** gera um SDP Offer e envia ao Relay: `[\"PEER_SIGNAL\", { target: \"Peer A\", signal: offer }]`.\n3. **Relay** localiza a conexão WebSocket de **Peer A** e repassa: `[\"PEER_SIGNAL_RELAY\", { from: \"Peer B\", signal: offer }]`.\n4. **Peer A** gera um SDP Answer e envia ao Relay: `[\"PEER_SIGNAL\", { target: \"Peer B\", signal: answer }]`.\n5. **Relay** repassa ao **Peer B**.\n6. Conexão P2P estabelecida via STUN/TURN.\n\n---\n\n## 6. Segurança e Integridade\n\n1. **Assinaturas Schnorr:** Clientes **OBRIGATORIAMENTE** devem validar a assinatura (`sig`) de cada evento recebido via P2P usando a biblioteca `noble-curves` ou similar. Se o ID do evento ou a assinatura forem inválidos, o peer remetente deve ser desconectado e reportado.\n2. **Reputação de Peer:**\n   - O Relay deve manter um score de reputação no Redis/DB.\n   - `+1` para cada evento validado e entregue (reportado via `PEER_STATS`).\n   - `-100` (banimento) para envio de assinaturas falsas.\n   - Decay temporal: Reputação diminui se o peer ficar offline.\n3. **Privacidade:** O uso de WebRTC expõe o endereço IP entre os peers. Clientes devem solicitar consentimento do usuário antes de ativar o modo P2P (\"Enable P2P Acceleration\").\n\n---\n\n## 7. Extensão NIP-11 (Relay Information)\n\nRelays compatíveis devem anunciar os limites do protocolo:\n\n```json\n{\n  \"supported_nips\": [1, 11, 95],\n  \"limitation\": {\n    \"p2p_enabled\": true,\n    \"p2p_max_connections_per_peer\": 10,\n    \"p2p_heartbeat_ms\": 30000\n  }\n}\n```\n\n---\n\n## 8. Pseudocódigo para Implementação em LLM\n\n### Handler de Mensagem (Servidor)\n```typescript\nfunction handleMessage(client, message) {\n  const [type, payload] = message;\n  switch(type) {\n    case \"PEER_REGISTER\":\n      return registerPeer(client, payload);\n    case \"PEER_CACHE_HAVE\":\n      return updateCacheTracker(client.id, payload.events);\n    case \"PEER_SIGNAL\":\n      const target = getClientById(payload.target_peer);\n      if (target) {\n        send(target, [\"PEER_SIGNAL_RELAY\", { from: client.id, signal: payload.signal_data }]);\n      }\n      break;\n    case \"REQ\":\n      handleStandardNip01(client, payload);\n      triggerSmartRouting(client, payload); // NIP-95 logic\n      break;\n  }\n}\n```\n\n### Handler de Recebimento P2P (Cliente)\n```javascript\npeer.on('data', data =\u003e {\n  const msg = JSON.parse(data);\n  if (msg.type === 'P2P_EVENTS') {\n    if (nostr.verifySignature(msg.event)) {\n      displayEvent(msg.event);\n      localCache.save(msg.event);\n    } else {\n      reportMaliciousPeer(msg.peer_id);\n    }\n  }\n});\n```\n\n---\n\n## 9. Fluxograma de Decisão (LLM Reasoning)\n\n1. **Input:** Filtro Nostr (ex: `{ \"kinds\": [1], \"limit\": 10 }`).\n2. **Relay Query:** Busca no DB local (Fast).\n3. **P2P Query:** Verifica se algum Super Peer enviou `PEER_CACHE_HAVE` recentemente com `kind: 1`.\n4. **Action:** Envia resultados do DB via WebSocket + `PEER_OFFER` para conectar aos Super Peers que têm mais eventos do mesmo tipo, visando futuras atualizações.\n5. **Result:** O cliente recebe os primeiros 10 eventos via WebSocket (baixa latência) e estabelece P2P para o fluxo contínuo (sustentabilidade).",
  "sig": "f05a3226845cae304c874d4def02dd15e083e88894328242362a61794bfbe0e6f28f971e979e09e56941d816841a0918e4405cf902458a8f9e4d6e1e39def38f"
}