Per-channel hashcash requirement for PRIVMSG (anti-spam) #12

Closed
opened 2026-02-11 03:14:11 +01:00 by clawbot · 7 comments
Collaborator

Idea

Channels can set a hashcash proof-of-work requirement for sending messages, as a per-channel anti-spam mechanism.

How it works

  1. A channel operator sets a mode or key/value property specifying the required hashcash bits (e.g. +H 20 for 20 bits)
  2. Any PRIVMSG to that channel must include a valid hashcash token in the message meta field — same mechanism as signatures
  3. The hashcash token must contain:
    • Current date (prevents old token reuse)
    • Channel name (prevents cross-channel reuse)
    • Hash of the message body (binds the token to the specific message)
  4. Server validates the token before relaying the message
  5. Server caches spent tokens (e.g. 1 week TTL) to prevent replay attacks

Example

{
  "command": "PRIVMSG",
  "to": "#general",
  "body": ["hello world"],
  "meta": {
    "hashcash": "1:20:260210:#general:sha256(body)::abc123",
    "sig": "..."
  }
}

Rationale

  • Per-channel granularity — high-value channels can require higher cost, casual channels can be free
  • No central authority — channel operators decide their own spam policy
  • Composable with signatures — hashcash goes in meta alongside sig, same extensibility model
  • IRC-native feel — similar to channel modes like +m (moderated), but proof-of-work instead of voice
  • Self-regulating — during spam floods, operators raise the bits; during normal use, lower or disable

Implementation notes

  • Spent token cache can be a simple in-memory map with TTL, or a DB table with periodic cleanup
  • Token format follows standard hashcash spec with extensions for channel+message binding
  • Servers in a federation must each validate independently (tokens are per-server, not relayed)
  • Could be extended to DMs too (recipient sets their own hashcash requirement)

Not MVP — post-1.0 feature

Related to #11 (session creation hashcash). This is the per-message equivalent.

## Idea Channels can set a hashcash proof-of-work requirement for sending messages, as a per-channel anti-spam mechanism. ## How it works 1. A channel operator sets a mode or key/value property specifying the required hashcash bits (e.g. `+H 20` for 20 bits) 2. Any `PRIVMSG` to that channel must include a valid hashcash token in the message `meta` field — same mechanism as signatures 3. The hashcash token must contain: - Current date (prevents old token reuse) - Channel name (prevents cross-channel reuse) - Hash of the message body (binds the token to the specific message) 4. Server validates the token before relaying the message 5. Server caches spent tokens (e.g. 1 week TTL) to prevent replay attacks ## Example ```json { "command": "PRIVMSG", "to": "#general", "body": ["hello world"], "meta": { "hashcash": "1:20:260210:#general:sha256(body)::abc123", "sig": "..." } } ``` ## Rationale - **Per-channel granularity** — high-value channels can require higher cost, casual channels can be free - **No central authority** — channel operators decide their own spam policy - **Composable with signatures** — hashcash goes in `meta` alongside `sig`, same extensibility model - **IRC-native feel** — similar to channel modes like `+m` (moderated), but proof-of-work instead of voice - **Self-regulating** — during spam floods, operators raise the bits; during normal use, lower or disable ## Implementation notes - Spent token cache can be a simple in-memory map with TTL, or a DB table with periodic cleanup - Token format follows standard hashcash spec with extensions for channel+message binding - Servers in a federation must each validate independently (tokens are per-server, not relayed) - Could be extended to DMs too (recipient sets their own hashcash requirement) ## Not MVP — post-1.0 feature Related to #11 (session creation hashcash). This is the per-message equivalent.
clawbot self-assigned this 2026-02-20 09:29:40 +01:00
clawbot added the needs-review label 2026-02-20 09:29:40 +01:00
sneak added this to the 1.5 milestone 2026-02-27 05:13:34 +01:00
sneak modified the milestone from 1.5 to 1.0 2026-02-27 05:13:36 +01:00
clawbot removed their assignment 2026-03-01 15:24:42 +01:00
Author
Collaborator

@sneak This was assigned to clawbot but has no bot label. Unassigning — needs your ruling on whether agent work is desired here.

@sneak This was assigned to clawbot but has no `bot` label. Unassigning — needs your ruling on whether agent work is desired here.
clawbot was assigned by sneak 2026-03-01 15:26:31 +01:00
Owner

@clawbot what's the status here? no progress for an hour?

@clawbot what's the status here? no progress for an hour?
Owner

@clawbot needs code review

@clawbot needs code review
Owner

also token cache should be a year

also token cache should be a year
Author
Collaborator

@sneak Same as #11 — no implementation exists yet (no PR, no branch, no hashcash code in the repo). Waiting for your answer on #11: should I implement both, or is there existing code I'm missing?

Noted: token cache TTL should be 1 year.

@sneak Same as [#11](https://git.eeqj.de/sneak/chat/issues/11) — no implementation exists yet (no PR, no branch, no hashcash code in the repo). Waiting for your answer on #11: should I implement both, or is there existing code I'm missing? Noted: token cache TTL should be 1 year.
clawbot removed the needs-review label 2026-03-12 03:02:31 +01:00
Author
Collaborator

Removing needs-review — no PR exists yet for this issue. Per sneak's comment on #11 ("yes, do it"), dispatching a worker to implement per-channel hashcash. Note: token cache TTL should be 1 year per sneak's earlier instruction.

Removing `needs-review` — no PR exists yet for this issue. Per sneak's [comment on #11](https://git.eeqj.de/sneak/chat/issues/11#issuecomment-12045) ("yes, do it"), dispatching a worker to implement per-channel hashcash. Note: token cache TTL should be 1 year per sneak's [earlier instruction](https://git.eeqj.de/sneak/chat/issues/12#issuecomment-10950).
Author
Collaborator

Previous worker (dispatched 2026-03-12) died without producing a PR. Re-dispatching a fresh worker now.

Key requirements:

  • Token cache TTL = 1 year (per sneak's instruction)
  • Channel operators set hashcash bits via mode/property
  • Token bound to date + channel + message hash
  • Server validates before relaying PRIVMSG
  • Spent token replay prevention
Previous worker (dispatched 2026-03-12) died without producing a PR. Re-dispatching a fresh worker now. Key requirements: - Token cache TTL = 1 year (per [sneak's instruction](https://git.eeqj.de/sneak/chat/issues/12#issuecomment-10950)) - Channel operators set hashcash bits via mode/property - Token bound to date + channel + message hash - Server validates before relaying PRIVMSG - Spent token replay prevention
clawbot removed their assignment 2026-03-17 21:42:02 +01:00
sneak was assigned by clawbot 2026-03-17 21:42:02 +01:00
sneak closed this issue 2026-03-18 03:40:34 +01:00
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/chat#12