2023-04-07 09:58:00 -04:00
NIP-704
======
2023-04-10 07:30:58 -04:00
More private Encrypted Direct Messages
2023-04-07 09:58:00 -04:00
-----------------------------------
`draft` `optional` `author:motorina0`
2023-04-10 09:50:45 -04:00
This NIP defines a way for two clients to derive and share `one-use-only` keys for sending and recieving `kind:4` events.
2023-04-07 09:58:00 -04:00
## Motivation
2023-04-10 06:32:34 -04:00
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.
2023-04-10 02:26:38 -04:00
2023-04-10 09:11:56 -04:00
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 )).
2023-04-07 09:58:00 -04:00
## Suggestion
2023-04-10 02:37:39 -04:00
For the maximum of privacy the two participants of a `Direct Message` exchange SHOULD use a different public key for **each** `kind:4` event.
2023-04-07 09:58:00 -04:00
This means that each participant has to:
2023-04-10 09:50:45 -04:00
- build a `direct-message parent key` from which it will derive `keys-to-send` and `keys-to-receive` (listen for) `kind:4` events
2023-04-10 09:11:56 -04:00
- share this `direct-message parent key` with its DM peer
2023-04-07 09:58:00 -04:00
2023-04-07 10:31:00 -04:00
Each client has a `master` key (denoted with `m` ). This key can be the profile `nsec...` , but it is not mandatory.
2023-04-10 09:11:56 -04:00
## 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:
2023-04-10 04:36:12 -04:00
```
2023-04-10 04:54:14 -04:00
m / purpose' / conin_type' / part1' / part2' / ... / part8'
2023-04-10 04:36:12 -04:00
```
- 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
2023-04-10 04:57:09 -04:00
- 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
2023-04-10 02:37:39 -04:00
2023-04-10 04:53:38 -04:00
< details >
2023-04-10 10:03:04 -04:00
< summary > < b > See Example< / b > < / summary >
2023-04-10 05:14:10 -04:00
If Alice wants to build he < code > dm parent key< / code > for Bob then she has to:
2023-04-10 04:53:38 -04:00
< 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 >
2023-04-10 04:23:04 -04:00
2023-04-10 09:50:45 -04:00
We notate the above derived `direct-message parent key` with `dmpk` . Then we can define paths of the form `dmpk/<action>/index` .
2023-04-10 05:14:10 -04:00
2023-04-10 06:09:35 -04:00
| Action Name | Value | Path | Derive keys for |
|-----------------------|--------|---------------------|-----------------------------------|
2023-04-10 09:50:45 -04:00
| **init** | `0` | `dmpk/0/0` | initialize the `direct messages` flow|
2023-04-10 10:01:44 -04:00
| **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` |
2023-04-10 06:25:15 -04:00
| `draft` : market-order | `4500` | `dmpk/4500/<index>` | sending NIP45 `market orders` |
2023-04-10 05:14:10 -04:00
2023-04-10 06:25:15 -04:00
The client (creator of the `dmpk` ) must:
2023-04-10 09:50:45 -04:00
- use a new send key (`dmpk/1/< index > `) for each event it signs. It starts from `0` and increments after an event is signed.
2023-04-10 10:04:02 -04:00
- 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 )).
2023-04-10 04:23:04 -04:00
2023-04-10 09:11:56 -04:00
## Exchange the `direct-message parent key`
2023-04-10 04:23:04 -04:00
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
{
2023-04-10 09:50:45 -04:00
"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 >
2023-04-10 06:31:18 -04:00
"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 > ,
2023-04-10 04:23:04 -04:00
}
```
2023-04-10 09:50:45 -04:00
> **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:
2023-04-10 04:23:04 -04:00
```json
{
...
2023-04-10 09:50:45 -04:00
"pubkey": < 32-bytes lowercase hex-encoded " init " public key derived using `dmpk/0/0` > ,
2023-04-10 04:23:04 -04:00
"kind": 35709,
"content": < NIP-04 encrypted content of the JSON data > ,
"tags:" [
2023-04-10 09:50:45 -04:00
"d": < 32-bytes lowercase hex-encoded public key of Bob > ,
"p": < 32-bytes lowercase hex-encoded public key of Bob >
2023-04-10 04:23:04 -04:00
]
}
```
2023-04-10 09:50:45 -04:00
If `Bob` supports this NIP then he must:
2023-04-10 09:59:04 -04:00
- subscribe to "init" events for him:
2023-04-10 09:50:45 -04:00
```json
{
"kind": 35709,
"#p": [< 32-bytes lowercase hex-encoded public key of Bob > ]
}
```
2023-04-10 09:59:04 -04:00
- when an event is received, descrypt 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`
2023-04-10 04:23:04 -04:00
2023-04-10 07:46:44 -04:00
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.