Thanks to visit codestin.com
Credit goes to github.com

Skip to content

design: bundled one-time-use Ghost Keys for per-action unlinkability #2

Description

@sanity

Motivation

Today a Ghost Key is anonymous at issuance (blind signing) but pseudonymous in use: reusing one key across messages or apps makes those uses cryptographically linkable to the same holder. See freenet/web#27 for the disclosure side.

One-time-use keys — a fresh Ghost Key per signed action — are the cleanest mitigation available short of ZK, and they avoid the substantial redesign a ZK-over-certificate approach would need.

Problem with naive per-transaction issuance

If each action required its own donation, the UX would be terrible and the project would look like a money grab even though per-action keys are genuinely the right privacy unit for many use cases.

Proposal

Decouple donation size from key count. A single donation issues a bundle of N blinded Ghost Keys in one pass. The user pays once for a supply and spends them locally, one per action, at their own pace. The donation server still never sees any key (blind signing is per-key), and bundle size is purely a policy / UX knob — it does not change the anonymity property at issuance.

Rough shape:

  • `ghost-key request --bundle 100` blinds 100 candidate keys, submits to the donation server, unblinds 100 signed certificates.
  • Local storage holds the bundle; the delegate / CLI draws one when the user takes a signable action.
  • The user refills when the bundle runs low. Replenishment is just another donation, so the economic model is unchanged — the project gets paid for a pack, not per stamp.

When not to use one-time-use keys

Per-action unlinkability is correct for votes, donations, ephemeral posts, anonymous feedback. It is wrong for apps where continuity is the feature — River room membership, long-lived reputation, anything where "this is the same person as yesterday" is load-bearing. For those, per-persona (one stable key, scoped to one context) is the right privacy unit.

The guidance, and what the CLI/delegate should support, is: match key lifetime to the privacy unit you actually want. Both modes need to be first-class.

Open questions

  1. What's a reasonable default bundle size? Tradeoff between UX friction (too few → constant refills) and donation-server workload / storage (too many per donation).
  2. Should bundles be tagged with a soft expiration to prevent long-term key hoarding breaking future format migrations?
  3. How does the delegate pick which key to spend — random, oldest-first, tagged-by-context? Random is safest against any ordering side-channel.
  4. How does a holder back up a bundle without creating a correlation oracle (e.g. cloud backup that sees all their keys)?
  5. Does the CLI need a "give me another" primitive that blinds + submits + unblinds in one shot, so apps can top up transparently?

Non-goals

  • ZK proof of certificate validity (separate, larger work item; tracked as future direction).
  • Changing the blind-signing protocol itself.
  • Making per-action the default for apps where continuity is correct.

Next step

Sketch the bundle-issuance CLI flow and delegate storage schema; confirm the donation server can sign N keys in one request without breaking its existing rate/abuse controls. Not urgent; driven by freenet/web#27 and follow-up demand from privacy-sensitive app authors.

[AI-assisted - Claude]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions