block / block/buzz

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

Open
#5,616 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.