diff --git a/76.md b/76.md new file mode 100644 index 0000000000..ae4d14820a --- /dev/null +++ b/76.md @@ -0,0 +1,85 @@ +NIP-76 +====== + +Trace Resistant Private Posts +------------------------------- + +`draft` `optional` `author:d-krause` + +Given the privacy concerns detailed in [A Cypherpunk's Manifesto](https://nakamotoinstitute.org/cypherpunk-manifesto/), additional measures can be taken in the NOSTR protocol to further maintain the privacy of NOSTR users when they desire it. This NIP defines a protocol that can be implemented by conforming relays and clients to maximize the privacy of a user's posts. + +## Goal +The goal of NIP-76 is to provide a way for users to share private data while also making it very difficult for governments or other third parties to scan content to identify posters and subscribers of the content. The third party "needing" this information must start with identifying the targeted entity **first**, *and only then* can they begin to work on obtaining access to their NOSTR private contents. + +## Two BIP-32 Extended Private Keys Required +Given a user's private key and 32 byte chain code, the user can generate an infinite supply of keys (see [BIP-32](https://bips.xyz/32])). In addition to the user's private profile key (`nsec`), NIP-76 requires two additional private extended keys, which we will call `addressesPrivateExtended`(a-prvx) and `secretsPrivateExtended`(s-prvx). + +[NIP-06](06.md) defines one manner in which the user's profile private key can be generated. Using this method, the client application could derive apx and spx as descendents of the profile key (`m/44'/1237'/0'/0/0`). For users that were not created with NIP-06, a random 32 byte chain code can be generated and stored by the client, and apx and spx can be derived from the resulting master private key. + +## Post Event + +The TRPP post is different from the Text Note event (`kind: 1`) in the following ways: +1. The is event `kind` is `17761`. +1. The `pubkey` is the derived pubkey from the `a-pubx/${index}` where index starts with 1 for the first post and increments + 1 for each successive post. (`a-pubx/0` is reserved for profile feed metadata.) +1. The event `content` is encrypted with `sha256(s-pubx/${index})` and is stored as a base64 string +1. The `sig` is computed the same, only the `a-prvx/${index}` for signing. + +## Event Storage Examples +Consider 3 users: Alice, Bob, and Charlie with the following key information, with only the pubkey stored in a relay: +| User | Pub Key | Address Extended Key | Secrets Extended Key +| --- | ----------- | ----------- | ----------- | +| Alice | A100...10A5 |**private:** aprvkd9fy7...98wfuwhec9h **public:** apub1r378f...7dsf38defs92|**private:** aprvks8jf7...9sh3lfu37d1 **public:** apuby2hd3p...mc73hf68s86s +| Bob | B200...F35C |**private:** aprvk4h8s7...6dsy3tab2yh **public:** apub2pc8t3...xv43m8d66dj|**private:** aprvbz75ak...pmn723n829 **public:** apubdsg5a76...88dutet577s +| Charlie | C300...19E4 |**private:** aprv987h7us...paw2pswee55e **public:** apubk22j8d6...pqww2ee4r56|**private:** aprvdg66d4...dfsg6ayyt5ts **public:** apubncs63ge5...re4s5d6s62f + +If Bob and Charlie wish to follow Alice's Private Posts, they would exchange address and secrets extended **public** keys. + +If Alice made 3 private posts in her timeline, all with the same content of "Hello World!", they would appear in the relay something like below (*`created_at` and `sig` ommitted from the samples for brevity*): +```json +{ + "kind": 17761 + "id": "01128889c6b6214981aa3c8cf812c82ecab4e64ab4b5e80f3bf78f59702710a5", + "pubkey": "3f22b2c92609f66d998d0f58907cf035f9fb9b9111e86c3fba4b11650424d1a8", + "content":"m0CPGvN59oWddLn4vYSne/kzt1oV0al8wJKj3bxIbqr6H0++VIFomqCC" +} +``` + +```json +{ + "kind": 17761 + "id": "cd142288be41c69f42c963248c7cb33ee2c5a9fdec590d714f3a200869c2d9d1", + "pubkey": "1d4be0bc944196f6f2b4a552e2b3e2c18f62fa5dfc429511bb6a07a8638a587a", + "content":"Im15XqMUqQvnpgRqGGskUtAlhuwQrZom2x7WO1JtkNzJ/BpJrhWZ3jFF" +} +``` +```json +{ + "kind": 17761 + "id": "1a8e8398580a2501b1cf4fdc0ba8bd70e93aeab49b41aa6a404e5c13b0884850", + "pubkey": "42ef3b0d118bef0b261b9e2ca8a77e997e91e160e951ced05eeee74853f3c500", + "content":"qP6oks7xkXSsYAUi+Y8JF3gXTejxkjxwXW0sWtARdRoBVZfM6nUumeLA" +} +``` +Thus, all of the content for Alice's post appear with a different pubkey, and encrypted with a different secret key, making it computationally unfeasible to identify what is in the posts or who created them without first having access to Alice's extended public addressing and secret keys. + +This prevents, or at least severely hinders, the ability for governments, corporations, and other third parties from scanning content, then identifying the users based on the content. One must know the user first, get permission to see the content, either from the user directly or via a legal action that compels the disclosure of the user's keys. + + + +## Communication between clients and relays + +Relays expose a websocket endpoint to which clients can connect. The relay communication of NIP-76 is the same as [NIP-01](01.md), with the addition of a new field `addresses` add to the subscription filters parameter. + +```json +{ + "kinds": [17761], + "addresses": , +} +``` +Upon receiving a `REQ` message, the relay SHOULD query its internal database and return events that match the filter by searching for children address starting at index 0 that have events with a pubkey equal to the `a-pubx/0..n`, until n reaches a point where no more events are returned. + + +Additional info +--------------- + +- [Proof of Concept (without NOSTR)](https://animiq.com) \ No newline at end of file diff --git a/README.md b/README.md index e45c531b54..b1f84c5637 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ NIPs stand for **Nostr Implementation Possibilities**. They exist to document wh - [NIP-56: Reporting](56.md) - [NIP-57: Lightning Zaps](57.md) - [NIP-65: Relay List Metadata](65.md) +- [NIP-76: Trace Resistant Private Posts](76.md) ## Event Kinds | kind | description | NIP |