-
Notifications
You must be signed in to change notification settings - Fork 598
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-112: Encrypted Group Events #580
Open
earonesty
wants to merge
20
commits into
nostr-protocol:master
Choose a base branch
from
earonesty:112
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
e9783b1
.
earonesty 5534326
.
earonesty 74a4105
Update 112.md
earonesty 95173c4
Add "relays" tag
earonesty e84206b
Update 112.md
earonesty 10aa362
chat is just one example
earonesty a3f9041
Update 112.md
earonesty d81b7c8
Update 112.md
earonesty e6d179c
Update 112.md
earonesty 389d9b9
Update 112.md
earonesty e55d358
Update 112.md
earonesty 154de4d
Update 112.md
earonesty a30eacc
Update 112.md
earonesty c2da954
Update 112.md
earonesty d1f3ce5
Update 112.md
earonesty f4b1ea6
Update 112.md
earonesty 15e273d
Update 112.md
earonesty 6a99be9
Update 112.md
earonesty 8454761
Update 112.md
earonesty 88ecba8
Update 112.md
earonesty File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
NIP-112 | ||
======= | ||
|
||
Encrypted Group Events | ||
---------------------- | ||
|
||
`draft` `optional` `author:earonesty` | ||
|
||
This NIP defines new event kinds for encrypted channels with optional forward secrecy guidelines. | ||
A channel is a way to create a private nostr sub-network, within which the protocol can operate normally | ||
visible only to users entrusted with a given decryption key. | ||
|
||
This NIP builds on the encryption from NIP-44, the gift-wrap of NIP-59 and the distributed chat channel management of NIP-28. It is similar to NIP-38, with the exception that gift-wrap is used on every message, and issues like metadata leakage and optional forward secrecy are addressed. | ||
|
||
It works by creating a shared secret that is used to encrypt the group or channel messages. | ||
Only the participants know that secret, so only such members can read/write to this group chat. | ||
This effectively hides metadata from external users. See drawbacks below. | ||
|
||
It reserves 8 event kinds (1059, 400-406) for immediate use. | ||
|
||
- [`1059`](https://github.com/nostr-protocol/nips/pull/468) - encrypted gift-wrap, can be used by many protocols | ||
- `400` - wrapped kind: create encrypted channel | ||
- `401` - wrapped kind: invite to encrypted channel | ||
- `402` - wrapped kind: change channel metadata | ||
- `403` - wrapped kind: send encrypted chat message | ||
- `404` - wrapped kind: moved to new channel | ||
- `405` - wrapped kind: delegate new owner | ||
- `406` - wrapped kind: accept owner delegation | ||
|
||
|
||
## Kind 1059: Encrypted Gift Wrap | ||
|
||
For all encrypted group events, the client first generates the approrpiate kind 4XX message, as below, and signs it with the user's identity key. | ||
|
||
Then they generate a new public/private keypair, and uses this to sign new kind 1059 message. | ||
|
||
The `content` of that message is a [NIP-44](https://github.com/nostr-protocol/nips/pull/574) encrypted JSON string. | ||
|
||
The content is encrypted using the public key of the destination (the chat room public key, or the invitee public key. | ||
|
||
All events called "wrapped-kind XX" refer to these kind 1059 gift wrapped events. | ||
|
||
For more information on gift-wrapping, see: [NIP-59](https://github.com/nostr-protocol/nips/pull/468) | ||
|
||
## Wrapped Kind 400: Create Encrypted channel | ||
|
||
Create a Encrypted event channel. | ||
|
||
In the channel creation `content` field, Client SHOULD include basic channel metadata (`name`, `about` and `picture`). | ||
|
||
This is akin to NIP-28, kind 40 but using gift-wrap encryption. | ||
|
||
On creating a channel, the creator MUST also generate a unique/new private-public key pair which will serve as the `shared-secret` for a given channel. | ||
|
||
This is the "destination pubkey" for the channel creation. | ||
|
||
A list of recommended relays SHOULD be added to the channel-create message | ||
|
||
```json | ||
{ | ||
"content": "{\"name\": \"Demo Channel\", \"about\": \"A test channel.\", \"picture\": \"https://placekitten.com/200/200\"}", | ||
"tags": [["r", "wss://relay-01"], ["r", "wss://relay-02"], ...]] | ||
} | ||
``` | ||
|
||
The wrapped INNER event id for the channel creation should be saved. This is the event id that will be used in all future INNER references to the channel creation. | ||
|
||
Channel creation events MUST be sent to the "destination pubkey" of the channel itself, not to any specific user. | ||
|
||
As a rule, this "destination pubkey" of the channel MUST used as the sole identifier and external filter that clients use to retrieve events for the channel. | ||
|
||
There are no other public tags or metadata, all other kinds and tags are "inner" (inside the wrapped message). | ||
staab marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Wrapped Kind 401: Invitation to Encrypted Channel | ||
|
||
Invitations are sent directly to the participants of the channel. | ||
|
||
```json | ||
{ | ||
"content": "optional personalized invitation message", | ||
"tags": [["e", "channel-create-event-id", "relay-url"], ["privkey", "channel-private-key"]] | ||
staab marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
``` | ||
|
||
When wrapping invitation messages, the destination pubkey is the user being invited, not the pubkey of the channel. The relay used should be one of that user's well-known relays. | ||
|
||
Additional relays can be recommended using "r" tags. | ||
|
||
## Wrapped Kind 402: Change channel metadata | ||
|
||
Update an encrypted channel's public metadata. | ||
|
||
Clients and SHOULD handle wrapped-kind 402 events similar to kind 33 `replaceable` events. Relays cannot distinguish this from other kind 1059 events. | ||
|
||
Clients SHOULD ignore kind wrapped-402 from pubkeys other than the current owner. | ||
|
||
The current owner of a channel is the pubkey that created the given channel using the corresponding wrapped-kind 400 event, or the current owner based on the 405-406 channel ownership delegation flow. | ||
|
||
In other words, only the owner of a channel can *effectively* send kind wrapped-402 events; kind 402 for any channel sent by other people, even participants of that channel, are ignored. | ||
|
||
Clients SHOULD support basic metadata fields: | ||
|
||
- `name` - string - Channel name | ||
- `about` - string - Channel description | ||
- `picture` - string - URL of channel picture | ||
|
||
Clients MAY add additional metadata fields. | ||
|
||
Clients MUST specify an "e" tag to identify the channel id. | ||
Clients SHOULD mark the "e" tag to recommend a relay where the original event can be found. | ||
Clients MAY replace the "r" tag set with a full list of new relays. | ||
|
||
There need be no overlap between the "e" relay and the "r" list. For example, if a group's channel is moving its relay set to a new set. | ||
|
||
```json | ||
{ | ||
"content": "{\"name\": \"Updated Demo Channel\", \"about\": \"Updating a test channel.\", \"picture\": \"https://placekitten.com/201/201\"}", | ||
"tags": [["e", "<channel-wrapped-400-event-id>", "wss://relay-url"]], | ||
} | ||
``` | ||
|
||
|
||
## Kind 403: Send encrypted message to encrypted group channel | ||
|
||
Clients SHOULD use marked "e" tags to specify if it is a reply message. | ||
|
||
Clients SHOULD use [NIP-10](10.md) marked "e" tags to recommend a relay and specify whether it is a reply or root message. | ||
|
||
Clients SHOULD append [NIP-10](10.md) "p" tags to replies. | ||
|
||
### Format | ||
|
||
Inner-root message: | ||
|
||
```json | ||
{ | ||
"content": <string>, | ||
"tags": [["e", "<kind_400_event_id>", "<relay-url-where-it-was-seen>", "root"], "<optional expiration tag>"] | ||
staab marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
``` | ||
|
||
Inner-reply to another message: | ||
|
||
```json | ||
{ | ||
"content": <string>, | ||
"tags": [ | ||
["e", "<kind_400_event_id>", "<relay-url>", "root"], | ||
["e", "<kind_403_reply_to_event_id>", "<relay-url>", "reply"], | ||
["p", "<pubkey>", "<relay-url>"] | ||
] | ||
} | ||
``` | ||
|
||
### Wrapped-kind 404: Removing Participants | ||
|
||
Send a Wrapped Kind 404 (similar to 401) | ||
|
||
Once a group is created, all participants know the shared-secret, so to remove a participant, we need to create a new group. | ||
|
||
To do, this the creator of the group issues a new 400 event. | ||
|
||
Then the creator sends out a kind 404 individually to every member of the new group, *excluding the removed participants*. | ||
|
||
```json | ||
{ | ||
"content": "optional friendly invite message", | ||
"tags": [ | ||
["e", "<previous-kind-400>", "<relay-url>"], | ||
["e", "<new-kind-400>", "<relay-url>"], | ||
["privkey", "<channel-private-key>"] | ||
] | ||
} | ||
``` | ||
Clients SHOULD ignore wrapped-kind 404 messages from anyone but the current owner of a group. | ||
|
||
Clients SHOULD ignore messages to the previous group that occur after their receive the first kind 404. In addition there is no longer a need to subscribe to the public keys of prior groups. | ||
|
||
Clients use kind 404 to find out which was the precursor channel(s) to this new channel, and should attempt to display all old and new channels in a chain seamlessly to the user as a unified channel history. | ||
|
||
Clients SHOULD consider the new channel metadata as authoritative. | ||
|
||
Clients MAY discard previous channel information, since it will no longer be used. | ||
|
||
### Wrapped-kind 405: Delegate new owner | ||
|
||
To do this the creator of the group sends out a wrapped-kind 405 to the main group public key. | ||
|
||
```json | ||
{ | ||
"content": "optional friendly invitation to own the group", | ||
"tags": [["e", "<400-event-id-of-group>", "<relay-url>"], ["p", "<public-key-of-delegate>"]] | ||
} | ||
``` | ||
Clients SHOULD ignore wrapped-kind 405 messages from anyone but the current "owner" of a group. | ||
Clients SHOULD ignore wrapped-kind 405 messages until they receive a 406 CLAIM message from the new "owner" of the group. | ||
|
||
### Wrapped-kind 406: Accept ownership transfer | ||
|
||
To do this the creator of the group sends out a wrapped-kind 405 to the main group public key. | ||
|
||
```json | ||
{ | ||
"content": "optional friendly hey, i'm in charge", | ||
"tags": [["e", "<event-id-of-405>", "<relay-url>"]] | ||
} | ||
``` | ||
Clients SHOULD ignore wrapped-kind 406 messages unless they are signed by the delegate in the associated 405 message | ||
Clients SHOULD treat accepted delegates as the new owner of the group for all 404 and 405 messages. | ||
|
||
## NIP-10 relay recommendations | ||
|
||
For [NIP-10](10.md) relay recommendations on replies and on channel creation info, clients generally SHOULD use the relay URL where the event was first seen, if known. | ||
|
||
|
||
Future extensibility | ||
-------------------- | ||
|
||
We reserve wrapped-event kinds 407-419 for other wrapped group events, such as delegation, moderation, mute, hide, etc. | ||
|
||
Motivation | ||
---------- | ||
|
||
This is the easiest way to allow the use of group events with select group of people, while hiding metadata, and preserving nostr's censorship resistence. | ||
|
||
Optional Forward Secrecy | ||
------------------------ | ||
|
||
Claims of "forward" secrecy in mobile applications can be disingenuous. Many mobile applications allow users to purchase a new phone and restore their account with historic messages intact - therefore this is not forward secrecy. | ||
|
||
True forward secrecy relies on servers reliably discarding the intermediate data - in addition to frequent key rotations, or prev-key ratcheting. A trusted server, for example, can be requested to discard old messages, by adding an optional NIP-40 expiration. | ||
|
||
### OPTIONAL forward secrecy extension | ||
|
||
The owner of a channel can add a "expiration" tag to the channel creation message. | ||
|
||
The owner of a channel who adds a "expiration" tag SHOULD issue a 404 message before the expiration. | ||
|
||
All members of a channel SHOULD also add a NIP-40 "expiration" tag to all messages sent to the channel using the duration (`expiration - created_at`) of the wrapped-400 create. | ||
|
||
Members of a channel MUST NOT send new messages if a 404 message has not been received before expiration. | ||
|
||
Servers SHOULD obey NIP-40 expiration tags. | ||
|
||
Provided that servers obey NIP-40 expiration tags, this will prevent an attacker from reading old group messages before the expiration. | ||
|
||
|
||
Drawbacks | ||
--------- | ||
Any member of the group can, implicitly, invite new members to the group, since they have the private key. Any member of a group can "dox" other members by publishing their wrapped messages. | ||
|
||
Any member of the group can spam the group, or otherwise DOS the group. | ||
|
||
If any single participant of the group chat leaks the shared secret ( whether intentionally or by accident), all the messages can then be decrypted by others until the next 400 and 404 rotation events. | ||
|
||
The use of optional frequent forward secrecy rotation events can mitigate these attacks, provided the server is compliant with the expiration times. | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.