Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NIP 404 - Ghost Events #1676

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

gu1p
Copy link

@gu1p gu1p commented Jan 8, 2025

This is a follow-up of a previous proposal I did in last November.
I tried to tackle most of issues that @Semisol, @pablof7z and @mikedilger have raised.

There is a "working" example (I'm not a cryptographer, have mercy on me): https://github.com/gu1p/nip404_demo

TL;DR;

NIP-404: Ghost Events

This NIP introduces Ghost Events—a protocol for creating events that are plausibly deniable with a ephemeral
nature, providing a weak binding to the author's identity. It leverages ring signatures, elliptic curve point-hashing, and a distance-based proof-of-work that references Bitcoin block hashes for chronological anchoring.

High-Level Mechanics

  • Ring Signature over exactly two keys:
    1. Your real key;
    2. A “mined” key—found by solving a proof-of-work puzzle (attacker) or randomly (by the real signer).
  • Distance-based PoW: The mined key’s public key must be within distance $\delta$ of a “challenge point” derived from your public key and a Bitcoin block hash.
  • Deniability: Verifiers can only tell that one of the two keys signed the event, not which one. Because all components are public, anyone can forge a Ghost Event referencing your key.

2. Detailed Protocol

2.1. Reference a Bitcoin Block

Pick a Bitcoin block $B$ with hash $H_B$ and timestamp $t_B$. This block anchors the event in time.

2.2. Derive a Challenge Point

  1. Take your main public key $P_A$ and concatenate it with $H_B$.
  2. Compute $S = \mathrm{SHA256}(P_A ,|, H_B)$.
  3. Map $S$ to secp256k1 (RFC 9380 “Hashing to Elliptic Curves”): $\mathrm{challenge_PK} = \mathrm{HashToCurve}(S).$

Anyone can verify this point by performing the same steps.

2.3. Pick a “Mined Key” $P_{\mathrm{mined}}$

  • Let $x_c$ be the $x$-coordinate of $\mathrm{challenge_PK}$.
  • Find $x_m$ such that $| x_m - x_c | \le \delta$ and $(x_m,y_m)$ is a valid secp256k1 point.
  • $\delta$ reflects the “difficulty” of finding such a key.

2.4. Create a Ring Signature

Form a ring of two public keys: ${P_A, P_{\mathrm{mined}}}$.
Use your real private key to sign, producing a ring signature that proves one of the private keys (either $\mathrm{sk}_A$ or $\mathrm{sk_mined}$) signed—but not which one.

2.5. Publish the Ghost Event

Publish a standard Nostr event (kind, content, etc.) plus tags:

  • ["ghost", "block-hash", "<H_B>"]
  • ["ghost", "block-hash-timestamp", "<t_B>"]

The event’s sig field is the ring signature. Verifiers can:

  1. Check validity of the ring signature over ${P_A, P_{\mathrm{mined}}}$.
  2. Recompute $\mathrm{challenge_PK}$ from $\langle P_A, H_B\rangle$.
  3. Measure how close $P_{\mathrm{mined}}$ is to $\mathrm{challenge_PK}$ (i.e., proof-of-work difficulty).
  4. Conclude: “Either Alice really signed, or someone else who found a matching $P_{\mathrm{mined}}$ did.”

@gu1p gu1p changed the title Feature/nip404 ghost events NIP 404 - Ghost Events Jan 8, 2025
@gu1p
Copy link
Author

gu1p commented Jan 8, 2025

An interactive example (edit: from here https://github.com/gu1p/nip404_demo/blob/master/main.py):

Alice: Today is a good day to post wild picture of me on Nostr! Maybe I will regret it later...
Alice: Let post as a ghost event!
Alice: I will set a PoW of 86400000000 tries for a 30% of success. It is an easy one!

{
  "id": "f9d32cace9ead9457d121041c4c17a779ab84cecf90f08d90ccacd9673f1bab4",
  "pubkey": "npub1r587vuykqhf8k7x4e06380edc7mr7pkz59r44tausmlwq970wkyqv9dh85",
  "created_at": 1736350383,
  "kind": 1,
  "tags": [
    [
      "ghost",
      "block-hash",
      "00000000000000000000c75dc9d3296751a8bb62b2463fbc49035ee75ab45f39"
    ],
    [
      "ghost",
      "block-hash-timestamp",
      1736264059
    ]
  ],
  "content": "Hi! This is Alice... Here is a picture of me drinking a beer!",
  "sig": "..."
  }

Bob: Wow! There is an event from Alice!
Bob: Let's check the signature to make sure it is from Alice
Bob: Alice didn't sign this event!
Bob: I see some ghost tags here...
Bob: It is a ghost event!
Bob: There are 2 possible signers!
Bob: Alice is one of the possible signers!
It was produced, allegedly, after the block a 00000000000000000000c75dc9d3296751a8bb62b2463fbc49035ee75ab45f39
Bob: It says that the block was mined at 1736264059
Bob: Let see if this block is real!
Bob: The block is real!
Bob: Let's check the PoW
Bob: The other signer is: npub1jktevjlge6vjp2yfaltrlvuv99th2uxaxy8eglvcsvr7e2r9h5lq2978dz
Bob: The challenge public key is: npub1jktevjldsr7kr52f90602gfhmc8cac9quq6yy8k9vy94w2qptsasz9cfps
Bob: Let's figure out how hard it was to mine the private key
Bob: The distance between the challenge and the alleged mined public key is 494635222290174920048599093528121665305037827746663102318405983997
Bob: For having 50% of chance of figuring out this key, the signer should have done 83496150448 tries
Bob: The signer should have mined 967231 keys per second, since the block was mined
Bob: It is not a hard PoW!

@gu1p gu1p marked this pull request as draft January 9, 2025 12:50
@gu1p
Copy link
Author

gu1p commented Jan 9, 2025

For compatibility, it's probably wiser to sign the event with a random one-time-use key and include the ring signature inside a tag resembling the delegated signing described in NIP-26

@mikedilger
Copy link
Contributor

I don't think you are going to get a lot of feedback on this because AFAIK none of us are cryptographers. But if it gets implemented in two places it should be merged so others can be compatible.

@gu1p
Copy link
Author

gu1p commented Jan 9, 2025

@mikedilger I tried to use common and well-stablished cryptography building-blocks. Nothing's new. Anyway, I'm hopeful of some constructive feedback. What do you personally think? I tried to address the concerns you guys had in my previous proposal.

  • I'm going to fix the signature thing I just mentioned, to be properly be compatible with Nostr.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants