From 1f69496741c428ba6e55df99fa9de15da90a229e Mon Sep 17 00:00:00 2001 From: ice-orestes <171555308+ice-orestes@users.noreply.github.com> Date: Fri, 9 Aug 2024 10:26:50 +0100 Subject: [PATCH 1/5] proposal for on-behalf of signing nip --- XXX.md | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 XXX.md diff --git a/XXX.md b/XXX.md new file mode 100644 index 0000000000..2590f7bec0 --- /dev/null +++ b/XXX.md @@ -0,0 +1,146 @@ +NIP-XXX +======= + +On Behalf of - Delegation (and revocation) of responsibility to other accounts +----- + +`draft` `optional` + +This NIP defines how a publisher public key (a media manager, another device, a sub account) can create events on-behalf of an author public key (the content author). Unlike NIP-26, here the attestations live in a repository controlled by the author, which is the `kind 0` replaceable profile event. + +Another application of this proposal is to abstract away the use of the 'root' keypairs when interacting with clients on different devices, for example, a user could generate new keypairs for each client they wish to use and authorize those keypairs with their root `kind 0` event, to generate events on behalf of their root profile, where the root keypair is stored in cold storage. This allows also the revocation of those attestations if needed. + +### References + +This proposal came together with inputs from many other proposals and discussions, but these are the main ones: + +[NIP-26: Delegated Event Signing](https://github.com/nostr-protocol/nips/blob/master/26.md)
+[NIP-46: Nostr Connect](https://github.com/nostr-protocol/nips/blob/master/46.md) + +[Why I don’t like NIP-26 as a solution for key management](https://fiatjaf.com/4c79fd7b.html)
+[Thoughts on Nostr key management](https://fiatjaf.com/72f5d1e4.html) + +[Stateless key rotation using a series of hidden commitments](https://github.com/nostr-protocol/nips/issues/103)
+[Key distribution, rotation, and recovery](https://github.com/nostr-protocol/nostr/issues/45)
+[Key rotation verified through root key attestation](https://github.com/nostr-protocol/nips/issues/116)
+[Trusted public-key-bundle attestations for key rotation and group definition](https://github.com/nostr-protocol/nips/issues/123) + +### Introducing the 'b' (on-Behalf) tag + +This NIP introduces a new tag: `b`, which is indexable by relays, and can be present in publisher (delegatee) events, provided that the author (delegator) attests with a delegation for that event `kind`, in its `kind 0` profile event, formatted as follows: + +```json +[ "b", ] +``` + +### Introducing the 'attest' (attestation) tag + +This NIP also introduces the new tag: `attest` which can be present multiple times in author's (delegator) `kind 0` event, formatted as follows: + +```json +[ + "attest", + , + +] +``` + +#### Delegation Attestation String + +The **Delegation Attestation** should be a string in the following format: + +``` +del:: +``` + +#### Revocation Attestation String + +The **Revocation Attestation** should be a string in the following format: + +``` +rev:: +``` + +> This way the author (delegator) can decide, depending on the use case, if it makes sense to keep the published content after delegation valid, by adding a `b` tag with a revocation attestation, or if is preferable to invalidate all content published by that keypair by simply removing the delegation attestation. + +##### Attestation String Components + +- `` is a coma separated list of event `kind`s that this attestation refers to +- `` is a UTC unix timestamp in seconds, after which that attestation produces effect + +##### Conflicting Attestations Resolution + +As the attestations are all timestamped, most conflicts should be resolved based on their timestamps, but in the rare event of the same timestamp in attestations for the same public key, the latest in the tags array should override the previous. + +#### Examples + +``` +# Delegator: +pubkey: 8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd + +# Delegatee: +pubkey: 477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396 +``` + +Delegation tag to allow delegatee to publish `kind 1` and `kind 7` events on-behalf of the delegator, present in delegator `kind 0` replaceable event: + +```json +"tags": [ + [ + "attest", + "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", + "del:1,7:1674834236" + ], + ... +] +``` + +When delegator (8e0d3d3e) decides to revoke that delegation for `kind 7` only, can just add another tag to his `kind 0` profile: + +```json +"tags": [ + ["attest", + "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", "del:1,7:1674834236"], + ["attest", + "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", "rev:7:1721934607"], + ... +] +``` + +Or in the case that the delegatee (477318cf) got compromised, and it is best to consider all content published from that key to be compromised, then the delegator simply removes the delegation attestation from his `kind 0` profile: + +```json +"tags": [ + ... +] +``` + +The delegatee (477318cf), while the delegator (8e0d3d3e) has a valid delegation attestation at its `kind 0` profile event, can publish on-behalf of the delegator, using the `b` tag on the event: + +```json +{ + "id": "e93c6095c3db1c31d15ac771f8fc5fb672f6e52cd25505099f62cd055523224f", + "pubkey": "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", + "created_at": 1677426298, + "kind": 1, + "tags": [ + [ + "b", + "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd" + ] + ], + "content": "Hello, world!", + "sig": "633db60e2e7082c13a47a6b19d663d45b2a2ebdeaf0b4c35ef83be2738030c54fc7fd56d139652937cdca875ee61b51904a1d0d0588a6acd6168d7be2909d693" +} +``` + +The event should be considered as published on-behalf of the author (8e0d3d3e), if at the timestamp `1677426298` the author had a valid delegation attestation on the `attest` tags in its `kind 0` profile event. If the `b` tag is not validated by an active delegation attestation, that content is considered invalid and relays and clients can ignore it. + +Clients should display the on-behalf events as if they were published directly by the delegator (8e0d3d3e). + + +#### Relay & Client Support + +Relays should answer requests such as `["REQ", "", {"authors": ["A"]}]` by querying both the `pubkey` and delegation `#b` tags `[1]` value. + +Relays SHOULD allow the delegator (8e0d3d3e) to delete the events published by the delegatee (477318cf). From 00c112aa44efc3f0ea588ca2479c15181caee6c3 Mon Sep 17 00:00:00 2001 From: ice-orestes <171555308+ice-orestes@users.noreply.github.com> Date: Fri, 16 Aug 2024 15:49:15 +0100 Subject: [PATCH 2/5] update to nip-51 lists and improve simplicity --- XXX.md | 282 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 198 insertions(+), 84 deletions(-) diff --git a/XXX.md b/XXX.md index 2590f7bec0..87b3df5762 100644 --- a/XXX.md +++ b/XXX.md @@ -1,21 +1,31 @@ NIP-XXX ======= -On Behalf of - Delegation (and revocation) of responsibility to other accounts +On-Behalf of - Simple Sub-Key Management ----- `draft` `optional` -This NIP defines how a publisher public key (a media manager, another device, a sub account) can create events on-behalf of an author public key (the content author). Unlike NIP-26, here the attestations live in a repository controlled by the author, which is the `kind 0` replaceable profile event. +This NIP defines a simple way for an Identity Sub-Key management system, including active, inactive and revoked public keys, for publishing On-Behalf of a master identity. -Another application of this proposal is to abstract away the use of the 'root' keypairs when interacting with clients on different devices, for example, a user could generate new keypairs for each client they wish to use and authorize those keypairs with their root `kind 0` event, to generate events on behalf of their root profile, where the root keypair is stored in cold storage. This allows also the revocation of those attestations if needed. +### Motivation + +The state of art now has two methods for enabling sub-key management: +- [NIP-26](https://github.com/nostr-protocol/nips/blob/master/26.md): Multiple key delegation and no revocation (just time bound) +- [NIP-41](https://github.com/nostr-protocol/nips/blob/master/41.md): More complete single key delegation and revocation (complex) + +Each of these methods has their own pros and cons, but there's a very common use case that is not covered by any of these methods completely, which is having a master identity that is secure (possibly in cold storage), that can whitelist and blacklist multiple public keys (one for each device or app, for example), that can be used individually (less common but interesting for media management companies) and can publish on-behalf of one or several master identities. + +Using [NIP-26](https://github.com/nostr-protocol/nips/blob/master/26.md) for this purpose doesn't allow for blacklisting (revocation), or alternatively requires time bound delegation, with new delegation signing at every expiry. On the other hand [NIP-41](https://github.com/nostr-protocol/nips/blob/master/41.md) is a more complete and complex identity management solution, but only allows for one active sub-key at any point in time, and that sub-key's only purpose is bound to the main identity. ### References This proposal came together with inputs from many other proposals and discussions, but these are the main ones: [NIP-26: Delegated Event Signing](https://github.com/nostr-protocol/nips/blob/master/26.md)
-[NIP-46: Nostr Connect](https://github.com/nostr-protocol/nips/blob/master/46.md) +[NIP-41: Identity Management](https://github.com/nostr-protocol/nips/blob/master/41.md)
+[NIP-06: Basic Key Derivation from Mnemonic Seed Phrase](https://github.com/nostr-protocol/nips/blob/master/06.md)
+[NIP-51: Lists](https://github.com/nostr-protocol/nips/blob/master/51.md) [Why I don’t like NIP-26 as a solution for key management](https://fiatjaf.com/4c79fd7b.html)
[Thoughts on Nostr key management](https://fiatjaf.com/72f5d1e4.html) @@ -25,122 +35,226 @@ This proposal came together with inputs from many other proposals and discussion [Key rotation verified through root key attestation](https://github.com/nostr-protocol/nips/issues/116)
[Trusted public-key-bundle attestations for key rotation and group definition](https://github.com/nostr-protocol/nips/issues/123) -### Introducing the 'b' (on-Behalf) tag +### Identity types + +For clarity in this NIP, we'll use the following identities to describe the actors that are involved in the examples and use cases: + +- **master**: the master account, the content owner or author +- **active**: an active sub account, device account, media manager or publisher account +- **inactive**: a sub account that has been inactivated (but not compromised) +- **revoked**: a sub account that has been revoked (it may have been compromised, and all events posted on-behalf of master need to be invalidated) + +### On-Behalf of Attestations List -This NIP introduces a new tag: `b`, which is indexable by relays, and can be present in publisher (delegatee) events, provided that the author (delegator) attests with a delegation for that event `kind`, in its `kind 0` profile event, formatted as follows: +This NIP introduces a replaceable event with `kind 10100`, which is used to keep a [NIP-51](https://github.com/nostr-protocol/nips/blob/master/51.md) list of `active`, `inactive` or `revoked` public keys, for publishing events on-behalf of a master account. The only valid tag in this list is `attest` tag as defined below. + +`.content` fields is unused and can be ignored if present. + +This list is owned by the master account, and can only be updated by an event signed by the master account itself, so never using a `b` on-behalf tag (see below), neither by [NIP-41](https://github.com/nostr-protocol/nips/blob/master/41.md) `p` tag in `kind 0`, nor using a [NIP-26](https://github.com/nostr-protocol/nips/blob/master/26.md) `delegation` tag. + +This list is evergrowing, so each update has to include all previous attestations unchanged, and add one or more attestations to the list, otherwise they should be considered invalid and ignored by clients and relays. + +### Tag `b` (on-Behalf) for events + +This NIP introduces a new tag: `b`, which is indexable by relays, and can be present in active account events, if attested at the on-behalf list above, formatted as follows: ```json -[ "b", ] +[ "b", ] ``` -### Introducing the 'attest' (attestation) tag +To prevent spam, only one `b` tag can be present in an event. + +If present and valid, the `b` tag will represent that clients and relays should consider that event as published by the master account specified in the `b` tag, instead of the one in the event `.pubkey` field. -This NIP also introduces the new tag: `attest` which can be present multiple times in author's (delegator) `kind 0` event, formatted as follows: +If an invalid `b` tag is present, clients and relays should disregard the event, as if it had an invalid signature. + +### Tag `attest` (attestation) for `kind 10100` list + +This NIP also introduces a new tag: `attest` which can be present multiple times in master account's `kind 10100` On-Behalf Of attestations list, formatted as follows: ```json [ - "attest", - , - + "attest", , , ] ``` -#### Delegation Attestation String +#### Active Attestation String -The **Delegation Attestation** should be a string in the following format: +The **Active Attestation** should be a string in the following format: ``` -del:: +"active:" ``` -#### Revocation Attestation String +`:` only required if an optional kinds list is present. Without a kinds list, the attestation is valid for all event kinds besides `kind 10100`. + +#### Inactive and Revoked Attestation String -The **Revocation Attestation** should be a string in the following format: +The **Inactive** or **Revoked Attestations** should be a string in the following format: ``` -rev:: +"inactive" ``` -> This way the author (delegator) can decide, depending on the use case, if it makes sense to keep the published content after delegation valid, by adding a `b` tag with a revocation attestation, or if is preferable to invalidate all content published by that keypair by simply removing the delegation attestation. +or -##### Attestation String Components +``` +"revoked" +``` -- `` is a coma separated list of event `kind`s that this attestation refers to -- `` is a UTC unix timestamp in seconds, after which that attestation produces effect +To purposely limit the creative use cases, so that it doesn't become very demanding to compute the final state of an account, `inactive` and `revoked` attestations invalidate all previous `active` attestations, and subsequent `active` attestations are considered invalid as well. -##### Conflicting Attestations Resolution +> This way the master account can decide, depending on the use case and criticality, if it makes sense to keep the published content valid, by adding an `inactive` attestation, or if it's preferable to invalidate all content published by that account, on its behalf, by adding a `revoked` attestation. -As the attestations are all timestamped, most conflicts should be resolved based on their timestamps, but in the rare event of the same timestamp in attestations for the same public key, the latest in the tags array should override the previous. +##### Subsequent Attestations Resolution -#### Examples +As the attestations are all timestamped, it is convention that a subsequent attestation overrides a prior one, but in the rare event of the same timestamp in attestations for the same public key, the latest in the tags array order should override the previous. -``` -# Delegator: -pubkey: 8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd +### Examples -# Delegatee: -pubkey: 477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396 -``` +- Considering: + ``` + master account: + 8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd -Delegation tag to allow delegatee to publish `kind 1` and `kind 7` events on-behalf of the delegator, present in delegator `kind 0` replaceable event: + active account: + 477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396 + ``` -```json -"tags": [ - [ - "attest", - "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", - "del:1,7:1674834236" +- Allow active account to publish `kind 1` and `kind 7` events on-behalf of the master account: + + ```json + { + "id": "567b41fc9060c758c4216fe5f8d3df7c57daad7ae757fa4606f0c39d4dd220ef", + "kind": "10100", + "pubkey": "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd", + "tags": [ + [ + "attest", 1674834236, + "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", + "active:1,7" + ] ], + "content": "", ... -] -``` - -When delegator (8e0d3d3e) decides to revoke that delegation for `kind 7` only, can just add another tag to his `kind 0` profile: - -```json -"tags": [ - ["attest", - "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", "del:1,7:1674834236"], - ["attest", - "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", "rev:7:1721934607"], + "sig": "a9a4e2192eede77e6c9d24ddfab95ba3ff7c03fbd07ad011fff245abea431fb4d3787c2d04aad001cb039cb8de91d83ce30e9a94f82ac3c5a2372aa1294a96bd" + } + ``` + +- The active account, while the master account has a valid active attestation at its `kind 10100` list, can publish on-behalf of the master account, using the `b` tag on the event: + + ```json + { + "id": "e93c6095c3db1c31d15ac771f8fc5fb672f6e52cd25505099f62cd055523224f", + "pubkey": "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", + "created_at": 1677426298, + "kind": 1, + "tags": [ + [ + "b", + "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd" + ] + ], + "content": "Hello, world!", + "sig": "633db60e2e7082c13a47a6b19d663d45b2a2ebdeaf0b4c35ef83be2738030c54fc7fd56d139652937cdca875ee61b51904a1d0d0588a6acd6168d7be2909d693" + } + ``` + + The event should be considered as published on-behalf of the master account, if at the timestamp `1677426298` the master account had a valid active attestation on its `kind 10100` list. If the `b` tag is not validated by an active attestation, that content is considered invalid and relays and clients can ignore it. + +- When master account decides to allow on-behalf active for all kinds: + + ```json + { + "id": "567b41fc9060c758c4216fe5f8d3df7c57daad7ae757fa4606f0c39d4dd220ef", + "kind": "10100", + "pubkey": "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd", + "tags": [ + ["attest", 1674834236, + "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", + "active:1,7"], + ["attest", 1721934607, + "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", + "active"] + ], + "content": "", ... -] -``` - -Or in the case that the delegatee (477318cf) got compromised, and it is best to consider all content published from that key to be compromised, then the delegator simply removes the delegation attestation from his `kind 0` profile: - -```json -"tags": [ + "sig": "a9a4e2192eede77e6c9d24ddfab95ba3ff7c03fbd07ad011fff245abea431fb4d3787c2d04aad001cb039cb8de91d83ce30e9a94f82ac3c5a2372aa1294a96bd" + } + ``` + +- Or otherwise, when master account decides to not allow on-behalf for `kind 7`, but keep `kind 1` active: + + ```json + { + "id": "567b41fc9060c758c4216fe5f8d3df7c57daad7ae757fa4606f0c39d4dd220ef", + "kind": "10100", + "pubkey": "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd", + "tags": [ + ["attest", 1674834236, + "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", + "active:1,7"], + ["attest", 1721934607, + "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", + "active:1"] + ], + "content": "", ... -] -``` - -The delegatee (477318cf), while the delegator (8e0d3d3e) has a valid delegation attestation at its `kind 0` profile event, can publish on-behalf of the delegator, using the `b` tag on the event: - -```json -{ - "id": "e93c6095c3db1c31d15ac771f8fc5fb672f6e52cd25505099f62cd055523224f", - "pubkey": "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", - "created_at": 1677426298, - "kind": 1, - "tags": [ - [ - "b", - "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd" - ] - ], - "content": "Hello, world!", - "sig": "633db60e2e7082c13a47a6b19d663d45b2a2ebdeaf0b4c35ef83be2738030c54fc7fd56d139652937cdca875ee61b51904a1d0d0588a6acd6168d7be2909d693" -} -``` - -The event should be considered as published on-behalf of the author (8e0d3d3e), if at the timestamp `1677426298` the author had a valid delegation attestation on the `attest` tags in its `kind 0` profile event. If the `b` tag is not validated by an active delegation attestation, that content is considered invalid and relays and clients can ignore it. - -Clients should display the on-behalf events as if they were published directly by the delegator (8e0d3d3e). + "sig": "a9a4e2192eede77e6c9d24ddfab95ba3ff7c03fbd07ad011fff245abea431fb4d3787c2d04aad001cb039cb8de91d83ce30e9a94f82ac3c5a2372aa1294a96bd" + } + ``` + +- In the case that master decides to not permit on-behalf publishing for that active account anymore, but keep the already published events, for instance if the device that was using that active account is being substituted, and that key safely destroyed: + + ```json + { + "id": "567b41fc9060c758c4216fe5f8d3df7c57daad7ae757fa4606f0c39d4dd220ef", + "kind": "10100", + "pubkey": "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd", + "tags": [ + ["attest", 1674834236, + "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", + "active:1,7"], + ["attest", 1721934607, + "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", + "active:1"], + ["attest", 1722343578, + "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", + "inactive"] + ], + "content": "", + ... + "sig": "a9a4e2192eede77e6c9d24ddfab95ba3ff7c03fbd07ad011fff245abea431fb4d3787c2d04aad001cb039cb8de91d83ce30e9a94f82ac3c5a2372aa1294a96bd" + } + ``` + +- Or instead, if the active account got compromised, and it is best to consider all content published from that account,on-behalf of master account, to be compromised: + + ```json + { + "id": "567b41fc9060c758c4216fe5f8d3df7c57daad7ae757fa4606f0c39d4dd220ef", + "kind": "10100", + "pubkey": "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd", + "tags": [ + ["attest", 1674834236, + "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", + "active:1,7"], + ["attest", 1721934607, + "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", + "active:1"], + ["attest", 1722343578, + "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", + "revoked"] + ], + "content": "", + ... + "sig": "a9a4e2192eede77e6c9d24ddfab95ba3ff7c03fbd07ad011fff245abea431fb4d3787c2d04aad001cb039cb8de91d83ce30e9a94f82ac3c5a2372aa1294a96bd" + } + ``` -#### Relay & Client Support +### Relay & Client Support -Relays should answer requests such as `["REQ", "", {"authors": ["A"]}]` by querying both the `pubkey` and delegation `#b` tags `[1]` value. +Relays should answer requests such as `["REQ", "", {"authors": ["A"]}]` by querying both the `pubkey` and on-behalf `#b` tags `[1]` value. -Relays SHOULD allow the delegator (8e0d3d3e) to delete the events published by the delegatee (477318cf). +Relays SHOULD allow the master account to delete the events published by the active, inactive or revoked accounts, whenever the events have the on-behalf `b` tag present. From 9ef8d654061c16ebe4129d160f68333a51bec123 Mon Sep 17 00:00:00 2001 From: ice-orestes <171555308+ice-orestes@users.noreply.github.com> Date: Thu, 5 Sep 2024 19:45:09 +0100 Subject: [PATCH 3/5] change attest tag to generic p tag for better alignment with standard --- XXX.md | 79 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 33 deletions(-) diff --git a/XXX.md b/XXX.md index 87b3df5762..8ae66766e4 100644 --- a/XXX.md +++ b/XXX.md @@ -46,13 +46,13 @@ For clarity in this NIP, we'll use the following identities to describe the acto ### On-Behalf of Attestations List -This NIP introduces a replaceable event with `kind 10100`, which is used to keep a [NIP-51](https://github.com/nostr-protocol/nips/blob/master/51.md) list of `active`, `inactive` or `revoked` public keys, for publishing events on-behalf of a master account. The only valid tag in this list is `attest` tag as defined below. +This NIP introduces a replaceable event with `kind 10100`, which is used to keep a [NIP-51](https://github.com/nostr-protocol/nips/blob/master/51.md) list of `active`, `inactive` or `revoked` public keys, for publishing events on-behalf of a master account. The only valid tag in this list is the `p` tag as defined below. `.content` fields is unused and can be ignored if present. This list is owned by the master account, and can only be updated by an event signed by the master account itself, so never using a `b` on-behalf tag (see below), neither by [NIP-41](https://github.com/nostr-protocol/nips/blob/master/41.md) `p` tag in `kind 0`, nor using a [NIP-26](https://github.com/nostr-protocol/nips/blob/master/26.md) `delegation` tag. -This list is evergrowing, so each update has to include all previous attestations unchanged, and add one or more attestations to the list, otherwise they should be considered invalid and ignored by clients and relays. +This list is ever growing, so each update has to include all previous attestations unchanged, and add one or more attestations to the list, otherwise they should be considered invalid and ignored by clients and relays. ### Tag `b` (on-Behalf) for events @@ -68,38 +68,40 @@ If present and valid, the `b` tag will represent that clients and relays should If an invalid `b` tag is present, clients and relays should disregard the event, as if it had an invalid signature. -### Tag `attest` (attestation) for `kind 10100` list +### Tag `p` (with attestation string) for `kind 10100` list -This NIP also introduces a new tag: `attest` which can be present multiple times in master account's `kind 10100` On-Behalf Of attestations list, formatted as follows: +This NIP also introduces a new attestation string for `p` tag. The `p` tag can be present multiple times in master account's `kind 10100` On-Behalf Of attestations list, formatted as follows: ```json [ - "attest", , , + "p", ,
, ] ``` +Field `main relay URL` can be omitted if not required or needed for accessing the sub account events, and in this case an empty string should be used in the second field of the `p` tag. + #### Active Attestation String The **Active Attestation** should be a string in the following format: ``` -"active:" +"active::" ``` -`:` only required if an optional kinds list is present. Without a kinds list, the attestation is valid for all event kinds besides `kind 10100`. +Last `:` is only required if an optional kinds list is present. Without a kinds list, the attestation is valid for all event kinds besides `kind 10100`. #### Inactive and Revoked Attestation String -The **Inactive** or **Revoked Attestations** should be a string in the following format: +The **Inactive** or **Revoked Attestations** should be a string in the following formats: ``` -"inactive" +"inactive:" ``` or ``` -"revoked" +"revoked:" ``` To purposely limit the creative use cases, so that it doesn't become very demanding to compute the final state of an account, `inactive` and `revoked` attestations invalidate all previous `active` attestations, and subsequent `active` attestations are considered invalid as well. @@ -130,9 +132,10 @@ As the attestations are all timestamped, it is convention that a subsequent atte "pubkey": "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd", "tags": [ [ - "attest", 1674834236, + "p", "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", - "active:1,7" + "", + "active:1674834236:1,7" ] ], "content": "", @@ -170,12 +173,14 @@ As the attestations are all timestamped, it is convention that a subsequent atte "kind": "10100", "pubkey": "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd", "tags": [ - ["attest", 1674834236, + ["p", "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", - "active:1,7"], - ["attest", 1721934607, + "", + "active:1674834236:1,7"], + ["p", "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", - "active"] + "", + "active:1721934607"] ], "content": "", ... @@ -191,12 +196,14 @@ As the attestations are all timestamped, it is convention that a subsequent atte "kind": "10100", "pubkey": "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd", "tags": [ - ["attest", 1674834236, + ["p", "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", - "active:1,7"], - ["attest", 1721934607, + "", + "active:1674834236:1,7"], + ["p", "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", - "active:1"] + "", + "active:1721934607:1"] ], "content": "", ... @@ -212,15 +219,18 @@ As the attestations are all timestamped, it is convention that a subsequent atte "kind": "10100", "pubkey": "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd", "tags": [ - ["attest", 1674834236, + ["p", "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", - "active:1,7"], - ["attest", 1721934607, + "", + "active:1674834236:1,7"], + ["p", "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", - "active:1"], - ["attest", 1722343578, + "", + "active:1721934607:1"], + ["p", "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", - "inactive"] + "", + "inactive:1722343578"] ], "content": "", ... @@ -228,7 +238,7 @@ As the attestations are all timestamped, it is convention that a subsequent atte } ``` -- Or instead, if the active account got compromised, and it is best to consider all content published from that account,on-behalf of master account, to be compromised: +- Or instead, if the active account got compromised, and it is best to consider all content published from that account,on-behalf of master account, to be compromised as well: ```json { @@ -236,15 +246,18 @@ As the attestations are all timestamped, it is convention that a subsequent atte "kind": "10100", "pubkey": "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd", "tags": [ - ["attest", 1674834236, + ["p", "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", - "active:1,7"], - ["attest", 1721934607, + "", + "active:1674834236:1,7"], + ["p", "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", - "active:1"], - ["attest", 1722343578, + "", + "active:1721934607:1"], + ["p", "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396", - "revoked"] + "", + "revoked:1722343578"] ], "content": "", ... From 9d9e98f463847f448b50a0df5ae10b29da6f2f14 Mon Sep 17 00:00:00 2001 From: ice-orestes <171555308+ice-orestes@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:51:29 +0100 Subject: [PATCH 4/5] rename to NIP-0b and add references in other files --- XXX.md => 0b.md | 4 ++-- 51.md | 1 + README.md | 5 ++++- 3 files changed, 7 insertions(+), 3 deletions(-) rename XXX.md => 0b.md (99%) diff --git a/XXX.md b/0b.md similarity index 99% rename from XXX.md rename to 0b.md index 8ae66766e4..0da70e4914 100644 --- a/XXX.md +++ b/0b.md @@ -1,5 +1,5 @@ -NIP-XXX -======= +NIP-0B +====== On-Behalf of - Simple Sub-Key Management ----- diff --git a/51.md b/51.md index 3792d7fe54..51f5840212 100644 --- a/51.md +++ b/51.md @@ -33,6 +33,7 @@ For example, _mute list_ can contain the public keys of spammers and bad actors | Interests | 10015 | topics a user may be interested in and pointers | `"t"` (hashtags) and `"a"` (kind:30015 interest set) | | Emojis | 10030 | user preferred emojis and pointers to emoji sets | `"emoji"` (see [NIP-30](30.md)) and `"a"` (kind:30030 emoji set) | | DM relays | 10050 | Where to receive [NIP-17](17.md) direct messages | `"relay"` (see [NIP-17](17.md)) | +| On-Behalf of | 10100 | [NIP-0b](0b.md) attestations list | `"p"` (pubkeys, with [NIP-0b](0b.md) attestation string) | | Good wiki authors | 10101 | [NIP-54](54.md) user recommended wiki authors | `"p"` (pubkeys) | | Good wiki relays | 10102 | [NIP-54](54.md) relays deemed to only host useful articles | `"relay"` (relay URLs) | diff --git a/README.md b/README.md index 0ebd9d22bd..ef738d1d45 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos - [NIP-07: `window.nostr` capability for web browsers](07.md) - [NIP-08: Handling Mentions](08.md) --- **unrecommended**: deprecated in favor of [NIP-27](27.md) - [NIP-09: Event Deletion Request](09.md) +- [NIP-0b: On-Behalf of (Simple Sub-Key Management)](0b.md) - [NIP-10: Conventions for clients' use of `e` and `p` tags in text events](10.md) - [NIP-11: Relay Information Document](11.md) - [NIP-13: Proof of Work](13.md) @@ -160,6 +161,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | `10050` | Relay list to receive DMs | [51](51.md), [17](17.md) | | `10063` | User server list | [blossom] | | `10096` | File storage server list | [96](96.md) | +| `10100` | On-Behalf of Attestations List | [0b](0b.md) | | `13194` | Wallet Info | [47](47.md) | | `21000` | Lightning Pub RPC | [Lightning.Pub][lnpub] | | `22242` | Client Authentication | [42](42.md) | @@ -247,10 +249,11 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | name | value | other parameters | NIP | | ----------------- | ------------------------------------ | ------------------------------- | ------------------------------------- | | `e` | event id (hex) | relay URL, marker, pubkey (hex) | [01](01.md), [10](10.md) | -| `p` | pubkey (hex) | relay URL, petname | [01](01.md), [02](02.md) | +| `p` | pubkey (hex) | relay URL, petname / attestation | [01](01.md), [02](02.md), [0b](0b.md) | | `a` | coordinates to an event | relay URL | [01](01.md) | | `d` | identifier | -- | [01](01.md) | | `-` | -- | -- | [70](70.md) | +| `b` | pubkey (hex) | -- | [0b](0b.md) | | `g` | geohash | -- | [52](52.md) | | `h` | group id | -- | [29](29.md) | | `i` | external identity | proof, url hint | [39](39.md), [73](73.md) | From faa1135102ab7534225d8e980e94fcc1472d050f Mon Sep 17 00:00:00 2001 From: ice-orestes <171555308+ice-orestes@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:23:07 +0100 Subject: [PATCH 5/5] fix nip-41 links to PR #1032 instead --- 0b.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/0b.md b/0b.md index 0da70e4914..c1472f8f8a 100644 --- a/0b.md +++ b/0b.md @@ -12,18 +12,18 @@ This NIP defines a simple way for an Identity Sub-Key management system, includi The state of art now has two methods for enabling sub-key management: - [NIP-26](https://github.com/nostr-protocol/nips/blob/master/26.md): Multiple key delegation and no revocation (just time bound) -- [NIP-41](https://github.com/nostr-protocol/nips/blob/master/41.md): More complete single key delegation and revocation (complex) +- [NIP-41](https://github.com/nostr-protocol/nips/pull/1032): More complete single key delegation and revocation (complex) Each of these methods has their own pros and cons, but there's a very common use case that is not covered by any of these methods completely, which is having a master identity that is secure (possibly in cold storage), that can whitelist and blacklist multiple public keys (one for each device or app, for example), that can be used individually (less common but interesting for media management companies) and can publish on-behalf of one or several master identities. -Using [NIP-26](https://github.com/nostr-protocol/nips/blob/master/26.md) for this purpose doesn't allow for blacklisting (revocation), or alternatively requires time bound delegation, with new delegation signing at every expiry. On the other hand [NIP-41](https://github.com/nostr-protocol/nips/blob/master/41.md) is a more complete and complex identity management solution, but only allows for one active sub-key at any point in time, and that sub-key's only purpose is bound to the main identity. +Using [NIP-26](https://github.com/nostr-protocol/nips/blob/master/26.md) for this purpose doesn't allow for blacklisting (revocation), or alternatively requires time bound delegation, with new delegation signing at every expiry. On the other hand [NIP-41](https://github.com/nostr-protocol/nips/pull/1032) is a more complete and complex identity management solution, but only allows for one active sub-key at any point in time, and that sub-key's only purpose is bound to the main identity. ### References This proposal came together with inputs from many other proposals and discussions, but these are the main ones: [NIP-26: Delegated Event Signing](https://github.com/nostr-protocol/nips/blob/master/26.md)
-[NIP-41: Identity Management](https://github.com/nostr-protocol/nips/blob/master/41.md)
+[NIP-41: Identity Management](https://github.com/nostr-protocol/nips/pull/1032)
[NIP-06: Basic Key Derivation from Mnemonic Seed Phrase](https://github.com/nostr-protocol/nips/blob/master/06.md)
[NIP-51: Lists](https://github.com/nostr-protocol/nips/blob/master/51.md) @@ -50,7 +50,7 @@ This NIP introduces a replaceable event with `kind 10100`, which is used to keep `.content` fields is unused and can be ignored if present. -This list is owned by the master account, and can only be updated by an event signed by the master account itself, so never using a `b` on-behalf tag (see below), neither by [NIP-41](https://github.com/nostr-protocol/nips/blob/master/41.md) `p` tag in `kind 0`, nor using a [NIP-26](https://github.com/nostr-protocol/nips/blob/master/26.md) `delegation` tag. +This list is owned by the master account, and can only be updated by an event signed by the master account itself, so never using a `b` on-behalf tag (see below), neither by [NIP-41](https://github.com/nostr-protocol/nips/pull/1032) `p` tag in `kind 0`, nor using a [NIP-26](https://github.com/nostr-protocol/nips/blob/master/26.md) `delegation` tag. This list is ever growing, so each update has to include all previous attestations unchanged, and add one or more attestations to the list, otherwise they should be considered invalid and ignored by clients and relays.