trilha

Sistemas Descentralizados/03 - Nostr4 min

Eventos e Chaves

Perguntas-guia
  • Que problema isso resolve?
  • Quando usar / quando NÃO usar?
  • Qual o principal trade-off?
  • Como isso falha em produção?

Conceito

O NIP-01 — o único obrigatório — cabe em duas ideias: uma identidade é uma chave e um dado é um JSON assinado. Tudo mais no Nostr é consequência.

A identidade

Um par de chaves secp256k1 (a mesma curva do Bitcoin), gerado offline, sem avisar ninguém:

Formato bruto Formato bech32 (NIP-19)
Privada 32 bytes hex nsec1...
Pública 32 bytes hex npub1...

O npub é o seu identificador global. Não há servidor no meio dele, não há registro, não há unicidade a negociar — o espaço de chaves é grande o bastante para que colisão não seja preocupação prática.

O bech32 do NIP-19 não é enfeite: o prefixo (npub/nsec) e o checksum existem para que colar a chave errada seja um erro detectável, e não uma chave privada publicada por acidente.

O evento

{
  "id":         "<sha256 da serialização canônica>",
  "pubkey":     "<chave pública do autor, 32 bytes hex>",
  "created_at": 1756400000,
  "kind":       1,
  "tags":       [["e", "<id do evento respondido>"],
                 ["p", "<pubkey mencionada>"]],
  "content":    "texto do post",
  "sig":        "<assinatura Schnorr sobre o id>"
}

Sete campos. É o protocolo inteiro.

O id é o conteúdo

O id não é atribuído por ninguém — é calculado:

id = sha256( json([0, pubkey, created_at, kind, tags, content]) )

Uma serialização canônica (sem espaços, escapes definidos, ordem fixa) garante que qualquer implementação chegue ao mesmo hash. Consequências, todas de graça:

  • Deduplicação trivial entre relays: mesmo id = mesmo evento
  • Imutabilidade: mudou uma vírgula, mudou o id, e a sig não bate mais
  • Idempotência: republicar não cria duplicata (ver 7. Kinds de Eventos e Mensagens)
  • Verificação independente: qualquer um confere sozinho, sem perguntar a nenhum servidor

Essa é a mesma ideia do Git (commit hash) e do IPFS (CID): endereçamento por conteúdo. Quando o identificador é derivado do dado, "esse dado foi adulterado?" deixa de ser uma pergunta que precisa de autoridade para responder.

As tags

Tags são arrays de strings, e o primeiro elemento é o nome. As duas fundamentais:

Tag Aponta para Uso
e um evento (por id) resposta, citação, reação
p uma pessoa (por pubkey) menção, destinatário

Tags de letra única minúscula são indexáveis pelos relays — dá para filtrar por elas ({"#e": [...]}). Tags maiores não são: servem como metadado carregado junto, sem custo de índice.

É um design de banco de dados exposto no protocolo: o formato do dado já diz o que é índice e o que é payload. Com isso, todo relay — em Go, Rust, TypeScript — chega ao mesmo esquema sem combinar nada.

O que o protocolo deliberadamente não define

Vale listar, porque a ausência é a parte instrutiva:

  • Não define ordem. created_at é declarado pelo autor e pode ser mentira.
  • Não define verdade. A assinatura prova autoria, nunca veracidade.
  • Não define unicidade. Nada impede dois eventos contraditórios do mesmo autor.
  • Não define quem pode publicar. Isso é política de relay, não de protocolo.

Trade-offs

A assinatura entrega autenticidade e integridade — e só. É pouco em comparação com um banco de dados, e é exatamente o suficiente para o problema que o Nostr escolheu resolver. Ver 1. Nostr vs Blockchain.

O created_at auto-declarado é o trade-off mais desconfortável. Sem consenso não há tempo objetivo, então o protocolo escolheu a solução honesta: deixar o autor declarar e não fingir garantia. Um autor pode datar um post no futuro para fixá-lo no topo dos feeds — e faz-se isso na prática. A defesa é do cliente (rejeitar timestamps absurdos), não do protocolo.

Em compensação, a ausência de estado global torna a implementação absurdamente simples: um relay funcional cabe em algumas centenas de linhas, e isso é o que torna relays baratos e, por consequência, abundantes e descartáveis — que é a fonte real da resistência à censura do Nostr.

Exemplo prático

Por que a assinatura, sozinha, já resolve censura de conteúdo.

Um relay hostil quer alterar seu post. Ele pode:

  • ❌ Editar o texto — o id muda, a sig não bate, todo cliente rejeita
  • ❌ Forjar um post seu — precisaria da sua nsec
  • ❌ Mudar a data — mesmo problema: quebra o hash e a assinatura
  • ✅ Não te entregar o evento — isso ele pode

Ou seja: um relay não consegue mentir, só consegue silenciar. E silenciar não funciona quando o cliente pergunta a outros cinco relays.

Aí está a economia inteira do design: assinatura resolve adulteração (problema criptográfico, resolvido de graça), e redundância resolve omissão (problema de disponibilidade, resolvido com fan-out barato). Nenhum dos dois precisou de consenso — e é por isso que o Nostr é ordens de grandeza mais barato que uma blockchain fazendo um trabalho parecido.

O que sobra sem solução é a terceira coluna: se todos os relays que você usa te omitirem, você sumiu. Ver 5. Limites do Nostr.

Relacionado


Parte de MOC Nostr · NIP-01

Buscar

Busca por título, seção e texto das notas