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
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
## 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. `id` ≠ `sha256(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 (`.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": [""], "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.
Contributor guide
Research direction
Start with the Buzz Desktop kind-9 authoring path and the relay's POST /query response. Reproduce the NIP-01 serialization and schnorr checks on text-only and attachment events, comparing them with the verifying kind-7 control events. Done means identifying where the delivered fields diverge and establishing a verifiable authorship path or documented limitation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- api, cryptography, security
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100