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

More private Encrypted Direct Messages #429

Open
wants to merge 37 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
b1a241b
doc: initial commit
motorina0 Apr 7, 2023
341a400
Update 704.md
motorina0 Apr 7, 2023
1d4977b
doc: add BIP32
motorina0 Apr 7, 2023
4ad341a
Merge branch 'dm-one-use-keys' of https://github.com/motorina0/nips i…
motorina0 Apr 7, 2023
c55a29f
fix: links
motorina0 Apr 7, 2023
6e10e94
doc: update motivation
motorina0 Apr 10, 2023
1696880
doc: update derivation path
motorina0 Apr 10, 2023
fe7536d
doc: update deriving
motorina0 Apr 10, 2023
fd91665
doc: add note
motorina0 Apr 10, 2023
4f266e6
doc: update notes
motorina0 Apr 10, 2023
149f7c1
doc: update exchange
motorina0 Apr 10, 2023
59dd72e
doc: phrasing
motorina0 Apr 10, 2023
0c302bf
doc: re-word
motorina0 Apr 10, 2023
206d25c
doc: nest the example
motorina0 Apr 10, 2023
65a28e7
doc: fix typo
motorina0 Apr 10, 2023
7f7b8b3
doc: fix
motorina0 Apr 10, 2023
1bb4c12
doc: reorder
motorina0 Apr 10, 2023
d4324ca
doc: stuff
motorina0 Apr 10, 2023
cc504c1
doc: actions table
motorina0 Apr 10, 2023
c5e91ab
doc: small changes
motorina0 Apr 10, 2023
65a4419
doc: send/receive keys
motorina0 Apr 10, 2023
6843912
doc: add note
motorina0 Apr 10, 2023
f5aa893
doc: re-word
motorina0 Apr 10, 2023
96d511a
doc: reference BIP-44 `address gap logic`
motorina0 Apr 10, 2023
3123a4b
doc: small
motorina0 Apr 10, 2023
865a4aa
Update 704.md
motorina0 Apr 10, 2023
391415f
Update 704.md
motorina0 Apr 10, 2023
37bacdf
doc: update title
motorina0 Apr 10, 2023
9688a76
doc: typo
motorina0 Apr 10, 2023
ef72990
Update 704.md
motorina0 Apr 10, 2023
ac6d5ef
doc: re-wrding
motorina0 Apr 10, 2023
84db35b
Update 704.md
motorina0 Apr 10, 2023
6510a69
Update 704.md
motorina0 Apr 10, 2023
c2a3ec2
Update 704.md
motorina0 Apr 10, 2023
0d66a29
Update 704.md
motorina0 Apr 10, 2023
8d1fc60
Update 704.md
motorina0 Apr 10, 2023
3d24dda
Update 704.md
motorina0 Apr 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions 704.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
NIP-704
======

More private Encrypted Direct Messages
-----------------------------------

`draft` `optional` `author:motorina0`

This NIP defines a way for two clients to derive and share `one-use-only` keys for sending and recieving `kind:4` events.

## Motivation
The content of `Direct Messages` [NIP-04](https://github.com/nostr-protocol/nips/blob/master/04.md) is encrypted, but everyone can see who is chatting with whom. Privacy wise this is far from ideal.

This NIP describes a way to obfuscate DM communications from the "general public", it does not deal with the relay tracking of clients (for that see [NIP-705](https://github.com/motorina0/nips/blob/republish_events/705.md)).

## Suggestion
For the maximum of privacy the two participants of a `Direct Message` exchange SHOULD use a different public key for **each** `kind:4` event.
This means that each participant has to:
- build a `direct-message parent key` from which it will derive `keys-to-send` and `keys-to-receive` (listen for) `kind:4` events
- share this `direct-message parent key` with its DM peer

Each client has a `master` key (denoted with `m`). This key can be the profile `nsec...`, but it is not mandatory.

## Derive the `direct-message parent key`
A client must generate multiple `direct-message parent keys`, one for each peer that it is communicating with. The [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) structure to be used is:
```
m / purpose' / conin_type' / part1' / part2' / ... / part8'
```

- this NIP defines the `purpose` `25709'` (`dm` -> `0x646d` -> `25709`) for deriving `Direct Messages` related keys
- nostr `coin_type'` is `1237'` (see [NIP-06](https://github.com/nostr-protocol/nips/blob/master/06.md))
- `part1' / part2' / ... / part8'` is the public key hex string (of the peer) split in 8 chunks:
- the reason for using the peer's (`Bob`) public key is to always arive at the same value even if prio state is lost
- the reason for splitting the public key is that each level of the path can have a max value of 2<sup>32</sup>-1


<details>
<summary><b>See Example</b></summary>
If Alice wants to build he <code>dm parent key</code> for Bob then she has to:
<ul>
<li>get the public key of `Bob` (in hex). Eg: <code>3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d</code></li>
<li>split the public key hex string in 8 chunks:</li>
- <code>3bf0c63f</code>, <code>cb934634</code>, <code>07af97a5</code>, <code>e5ee64fa</code>, <code>883d107e</code>, <code>f9e55847</code>, <code>2c4eb9aa</code>, <code>aefa459d</code>
<li>derive the <code>dm parent key</code>: <code>m/25709'/1237'/3bf0c63f'/cb934634'/.../aefa459d'</code></li>
</ul>
</details>

We notate the above derived `direct-message parent key` with `dmpk`. Then we can define paths of the form `dmpk/<action>/index`.

| Action Name | Value | Path | Derive keys for |
|-----------------------|--------|---------------------|-----------------------------------|
| **init** | `0` | `dmpk/0/0` | initialize the `direct messages` flow|
| **send** | `1` | `dmpk/1/<index>` | sending `direct messages` |
| **receive** | `2` | `dmpk/2/<index>` | receiving `direct messages` |
| `draft`: republish | `3` | `dmpk/3/<index>` | sending `republish events` |
| `draft`: market-order | `4500` | `dmpk/4500/<index>` | sending NIP45 `market orders` |

The client (creator of the `dmpk`) must:
- use a new send key (`dmpk/1/<index>`) for each event it signs. It starts from `0` and increments after an event is signed.
- create filters for the public keys it expects to receive messages to (`dmpk/2/<index>`). It is recommended to listen for the next `10` public keys and increment the index once a key is used (see [BIP-44 address gap logic](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#user-content-Address_gap_limit)).

## Exchange the `direct-message parent key`
If `Alice` wants to signal `Bob` that she is ready to use this NIP (for more privacy) she must:
- build a JSON data of the form:
```json
{
"pubkey": <32-bytes lowercase hex-encoded public key of Alice (public profile key)>
"dmpk": <32-bytes lowercase hex-encoded direct-message parent key>,
"shared_secret_hash": <32-bytes lowercase hex-encoded sha256 of the shared secret>
"send_index": <integer (optional), the index of the last key used to sign an event>,
"receive_index": <integer (optional), the index of the last key an event was received to>,
}
```
> **Note** `send_index` and `receive_index` are optional, but they help the client a lot in knowing what the state is. Otherwise (when an account is retored) the client would have to scan the public keys until unused ones are found (similar to [BIP-44 address gap logic](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#user-content-Address_gap_limit)).

- publish a `Parameterized Replaceable Event` ([NIP-33](https://github.com/nostr-protocol/nips/blob/master/33.md)) of the form:

```json
{
...
"pubkey": <32-bytes lowercase hex-encoded "init" public key derived using `dmpk/0/0`>,
"kind": 35709,
"content": <NIP-04 encrypted content of the JSON data>,
"tags:" [
"d": <32-bytes lowercase hex-encoded public key of Bob>,
"p": <32-bytes lowercase hex-encoded public key of Bob>
]
}
```

> **Note**: `Alice` must use the "init" (`dmpk/0/0`) public key for signing the event so that there is no visible interaction between her and `Bob`

If `Bob` supports this NIP then he must:
- subscribe to "init" events for him:
```json
{
"kind": 35709,
"#p": [<32-bytes lowercase hex-encoded public key of Bob>]
}
```
- when an event is received, decrypt the content, verify the `shared_secret_hash` against `Alice's` public key
- decide if it wants to communicate with `Alice`. If yes, it should publish its own `kind:35709` for `Alice`

Alice must also listen for `"kind": 35709` to her.
After both `Alice` and `Bob` have published the `kind: 35709` event, they can start to publish and listen to events using the `one-use-only` keys.