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-24: Private Messages #56

Closed
100 changes: 100 additions & 0 deletions 24.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
NIP-24
======

Private, Encrypted Direct Messages
----------------------------------

`draft` `optional` `author:jeffthibault`

This NIP defines a scheme for clients to send and receive [NIP-04](https://github.com/nostr-protocol/nips/blob/master/04.md) direct messages more privately.

Part 1: Decoy Key Proof Event
-----------------------------

A special event with kind 12, meaning `Decoy Key Proof` is defined similar to a NIP-04 event except the the unencrypted content MUST be a JSON-stringified object with the following structure:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A special event with kind 12, meaning `Decoy Key Proof` is defined similar to a NIP-04 event except the the unencrypted content MUST be a JSON-stringified object with the following structure:
A special event with kind 12, meaning `Decoy Key Proof` is defined similar to a NIP-04 event except the the content (shown here unencrypted) MUST be a JSON-stringified object with the following structure:

@jeffthibault I see. This phrasing would make it more clear, at least for me.

```
{
"msg": "dk:<a 32 byte, hex-encoded public key>",
"pk": "<32 byte, hex-encoded public key of the event creator>",
"sig": "<64 byte, hex-encoded signature of the sha256 hash of <msg>>"
}
```

The event MUST contain only one `"p"` tag for the intended recipient.

This event allows users to prove to someone else that they will send NIP-04 messages from a decoy public key and also verify when someone else attests to using a decoy public key for NIP-04 messages.

Part 2: Protocol
----------------

**Definitions**<br>
`S[-]` = Sender's Nostr private key (256 bit integer)<br>
`S[+]` = Sender's Nostr public key (256 bit integer)<br>
`R[-]` = Recipient's Nostr private key (256 bit integer)<br>
`R[+]` = Recipient's Nostr public key (256 bit integer)<br>
`SR[ss]` = Sender and Recipient's shared secret = `ECDH(S[-], R[+])` or `ECDH(R[-], S[+])` (256 bit integer)<br>

`S[d-]` = Sender's decoy private key (256 bit integer)<br>
`S[d+]` = Sender's decoy public key (256 bit integer)<br>
`R[d+]` = Recipient's decoy public key (256 bit integer)<br>

`RDIH` is the `Recipients's Decoy Inbox Hash`. It is known only by the sender and recipient because it is defined as the 32 byte, hex-encoded digest of `SHA256(SR[ss] + R[+])`.

### Sending

**Step 1**:<br>
For each new recipient, R, they message with, the sender MUST create a decoy private key, `S[d-]`, defined as `S[-] + SR[ss]`. The sender must also create a "throwaway key pair", `T[-]` and `T[+]`.

**Step 2**:<br>
Note: If the sender has already sent the recipient a `Decoy Key Proof` event (defined in Part 1), this step can be ignored.

The sender MUST send a `Decoy Key Proof` event with the unencrypted content set as a JSON-stringified object structured like so:
```
{
"msg": "dk:<S[d+]>",
"pk": "<S[+]>",
"sig": "<64 byte, hex-encoded signature of the sha256 hash of <msg> using <S[-]>>"
}
```

- `content` for the event is encrypted with the shared secret between `T[-]` and `R[+]`.<br>
- `pubkey` for the event is the throwaway public key, `T[+]`.<br>
- `tags` for the event is `[["p", <R[+]>]]`.<br>
- The event is signed with the throwaway private key, `T[-]`.<br>

**Step 3**:<br>
The sender sends standard NIP-04 events to the recipient via the `RDIH`.

- `content` for the NIP-04 events is encrypted with `SR[ss]`.<br>
- `pubkey` for the NIP-04 events is `S[d+]`.<br>
- `tags` for the NIP-04 events is `[["p", <RDIH>]]`.<br>
- The NIP-04 events are signed with `S[d-]`.<br>

### Receiving

**Step 1**:<br>
The recipient MUST subscribe to all `Decoy Key Proof` events intended for them like so:<br>
`["REQ", "decoy-key-proofs", {"kinds": [12], "#p": [<R[+]>]}]`

**Step 2**:<br>
Upon receiving a `Decoy Key Proof` event, the recipient MUST decrypt the content and verify the message in which the sender has attested to their decoy public key. Once the verification is complete, the recipient SHOULD save a mapping between the sender's real public key and decoy public key locally.

**Step 3**:<br>
The recipient MUST create a subscription for NIP-04 events sent to `RDIH` from the sender's decoy public key:<br>
`["REQ", "dms-with-sender", {"kinds": [4], authors=[<S[d+]>, <R[d+]>], "#p": [<RDIH>]}]`

Motivation
----------

NIP-04 is flawed because only event content is encrypted and not the metadata about it, and by the nature of Nostr as a protocol designed for public communication in general anyone is able to query relays for any event they want -- thus it's possible to anyone to track conversations between any other Nostr users, not exactly what they're saying, but to whom they're chatting and how often.

Privacy Analysis
----------------

When adhering to this NIP for direct messaging on Nostr, the only information that is available to an outside observer is that someone received a `Decoy Key Proof` event but there is nothing conclusive that can be discerned from that because the sending pubkey is obfuscated and the recipient might ignore it. To an outside observer, all the subsequent NIP-04 events are being sent from and to seemingly random keys.

Acknowledgements
----------------

@vinliao - for proposing an initial idea in https://github.com/nostr-protocol/nostr/issues/69<br>
@fiatjaf - for the `Motivation` section, it is taken from https://github.com/nostr-protocol/nips/blob/nip-21-non-public-dms/21.md `Rationale` section. See that for more information.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh
- [NIP-16: Event Treatment](16.md)
- [NIP-20: Command Results](20.md)
- [NIP-22: Event created_at Limits](22.md)
- [NIP-24: Private Messages](24.md)
- [NIP-25: Reactions](25.md)
- [NIP-26: Delegated Event Signing](26.md)
- [NIP-28: Public Chat](28.md)
Expand All @@ -37,6 +38,7 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh
| 4 | Encrypted Direct Messages | [4](04.md) |
| 5 | Event Deletion | [9](09.md) |
| 7 | Reaction | [25](25.md) |
| 12 | Decoy Key Proof | [24](24.md) |
| 40 | Channel Creation | [28](28.md) |
| 41 | Channel Metadata | [28](28.md) |
| 42 | Channel Message | [28](28.md) |
Expand Down