{"id":"88f58c38a2fe467dcb776ff0569cad655d4fda3be9f514e44e15f5675667f36a","pubkey":"0461fcbecc4c3374439932d6b8f11269ccdb7cc973ad7a50ae362db135a474dd","created_at":1783010467,"kind":30817,"tags":[["d","private-streams"],["title","Private Streams"],["alt","Nostr Implementation Possibility: Private Streams"],["k","1059","Giftwrap"],["client","NostrHub"]],"content":"# Private Streams\n\nPrivate streams can be created on Nostr between multiple parties by sharing a private key between all participants.\n\nAll participants sign NIP-59 giftwrap events with the shared key and publish them to relays. Participants with the key can query the stream by its public key:\n\n```json\n{ \"kinds\": [1059], \"authors\": [\"<stream pubkey>\"] }\n```\n\nTo join a private stream, people share invite links. The invite link results in the private key.\n\n## Stream Event\n\nA stream event is a kind 1059 event. It appears to be a regular giftwrap, blending in with other giftwrap traffic, but it's actually not a regular giftwrap.\n\n```json\n{\n  \"id\": \"<id>\",\n  \"kind\": 1059,\n  \"pubkey\": \"<stream pubkey>\",\n  \"content\": nip44_encrypt({\n    \"id\": \"<id>\",\n    \"kind\": 20013,\n    \"pubkey\": \"<real author's pubkey>\",\n    \"content\": nip44_encrypt({\n      \"id\": \"<id>\",\n      \"kind\": 9,\n      \"pubkey\": \"<real author's pubkey>\",\n      \"content\": \"Hey chat!\",\n      \"tags\": [],\n      \"created_at\": 1686840217,\n    }),\n    \"tags\": [],\n    \"created_at\": 1686840217,\n    \"sig\": \"<real author's signature>\"\n  }),\n  \"tags\": [\n    [\"p\", \"<ephemeral pubkey>\"]\n  ],\n  \"created_at\": 1686840217,\n  \"sig\": \"<stream signature>\"\n}\n```\n\n- Unlike NIP-59, which uses ephemeral authors and fixed \"p\" tags, streams use fixed authors and ephemeral \"p\" tags. It's reversed.\n- Unlike NIP-59, the giftwrap content is encrypted to the stream key, not to the \"p\" tagged key.\n- Unlike NIP-59, the seal event is kind 20013 instead of kind 13 to avoid storage by relays.\n- Unlike NIP-59, `created_at` should not be altered or tweaked.\n\n## Deletions\n\nTo prevent participants from deleting each-other's giftwraps, relays should prevent giftwrap deletions by author. This is semantically correct for NIP-59, which already requires that relays *allow* deletion by the \"p\" tagged user. Giftwraps are owned by the recipient, not the sender. Therefore, clients should use at least one relay that rejects giftwrap deletions.\n\nUsers can delete their content in streams by sending giftwrapped kind 5 deletion events to the stream. Users can also delete their own giftwraps by \"p\" tag (on NIP-59 supporting relays) if the client saves the ephemeral key.\n\n## Removing Participants\n\nTo remove a participant, a new stream must be created. This can happen automatically, with clients upgrading an existing chatroom to a new stream. Events would be combined from both the old and new streams into a single chatroom.","sig":"3f032a50d32d3ee59361e0f0660b2a34cd405e99acd70223b31db9d07ebed5c8c2772812635c2df3437b4a5251d8799cd2f535cbaebe6e6a00366c7d61b07730"}