Skip to content

Kind-9 messages authored in Buzz Desktop cannot be verified by third parties — id ≠ sha256(NIP-01 serialization), and sig matches neither the stated nor the recomputed id #5616

Description

@luthen-seas

Summary

A kind-9 channel message composed and sent from Buzz Desktop, fetched back via the relay's POST /query, fails every NIP-01 verification a third party can perform:

  1. idsha256(json([0, pubkey, created_at, kind, tags, content])) over the delivered fields
  2. schnorr.verify(sig, id, pubkey)false (signature does not verify over the stated id)
  3. schnorr.verify(sig, recomputed_id, pubkey)false (nor over the recomputed one)

This holds for text-only messages and for messages with attachments alike — the imeta enrichment is not the cause. Kind-7 reactions from the same community, fetched the same way, verify correctly (id recomputes, sig valid), so signing is not uniformly broken; it appears specific to the Desktop kind-9 authoring path.

Environment

  • Buzz Desktop 0.5.x (macOS), hosted relay (<community>.communities.buzz.xyz)
  • Events fetched via POST /query with NIP-98 auth; verification with @noble/curves schnorr (BIP-340) over the sha256 of the canonical NIP-01 serialization — the same code path that verifies this community's kind-7 reactions successfully every day

Reproduction (~2 minutes)

  1. In Buzz Desktop, post any message into a channel (no attachments needed).
  2. Fetch it back: POST /query with [{ "kinds": [9], "#h": ["<channel-id>"], "since": ... }].
  3. Recompute the id: sha256(JSON.stringify([0, pubkey, created_at, kind, tags, content])) over the delivered fields — it will not equal the delivered id.
  4. schnorr.verify(sig, id, pubkey) and schnorr.verify(sig, recomputed_id, pubkey) — both false.

Observed on four separate messages (three with attachments, one text-only), captured byte-exact by redirecting the query response to a file. As a control, kind-7 reactions fetched from the same relay in the same session verify correctly.

One possibly related observation: the delivered content shows formatting the author did not type (paragraphs re-indented with two leading spaces, whitespace-bearing blank lines), suggesting the content is transformed somewhere between composition and delivery.

Expected

Per NIP-01 — and Buzz's own framing that every message is a signed event — a delivered event should verify: the id should be the hash of its serialized fields, and the sig should verify over that id under the delivered pubkey.

Guess at the cause

The shape of the failure (sig valid under no checkable combination, pubkey delivered as the author's identity key) is what you'd see if a device key signs the event and the relay rewrites pubkey to the author's identity key on delivery, possibly alongside a content transform. If that's the design, is there a documented way for a third party to verify authorship — a delegation/attestation tag binding device keys to identity keys, or an endpoint exposing the binding?

Why it matters

Any integration that verifies events before acting on them — bots, bridges, moderation tooling, audit systems — currently has to choose between trusting the relay's word for authorship or ignoring every Desktop-authored message. We hit this building a bot that imports content posted by allowlisted team members: the signature gate we wanted had to be replaced with relay-membership trust, with a pinned test watching for the day verification starts passing.

Happy to share sanitized event JSON (the messages are from a private channel) or run diagnostics against a test community if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions