Compare commits

...

22 Commits

Author SHA1 Message Date
Pablo Fernandez
b6a524db0e justice 2023-11-16 19:11:46 +00:00
Pablo Fernandez
68b27f6574 increase time delay to 60-days 2023-10-20 10:21:35 +03:00
Pablo Fernandez
30dd53b51b Update 41.md
Co-authored-by: fiatjaf_ <fiatjaf@gmail.com>
2023-10-20 14:13:31 +07:00
Pablo Fernandez
b86ad6f627 mute mute 2023-10-19 16:44:42 +03:00
Pablo Fernandez
d6074050e6 update readme 2023-10-19 14:44:45 +03:00
Pablo Fernandez
651be3778f Update 41.md
Co-authored-by: fiatjaf_ <fiatjaf@gmail.com>
2023-10-19 18:41:41 +07:00
Pablo Fernandez
b483eb8b7b Update 41.md
Co-authored-by: fiatjaf_ <fiatjaf@gmail.com>
2023-10-19 18:40:52 +07:00
Pablo Fernandez
9e15edba1c add optional mute tag 2023-10-19 11:50:05 +03:00
Pablo Fernandez
3b1d74e116 update README 2023-10-19 11:40:49 +03:00
Pablo Fernandez
b3920f76b4 wip 2023-10-18 15:03:28 +03:00
fiatjaf
cf672b764b remove useless "block" tag on OTS. 2023-10-17 07:38:53 -03:00
Mike O'Bank
202e18f2b2 Nip 06 test vectors (#819) 2023-10-12 10:31:58 -03:00
fiatjaf_
09ffb951c6 rework NIP-03 so it is actually usable (#804)
* rework nip-03 to be actually useful and usable.
* fixes.
* add ots verification flow.
2023-10-11 10:17:43 -03:00
Don
324c7aafdc Change wording to imply that reactions can target any event (#815)
* kind:17 generic reactions.

* `kind 7` is available for all kind events.

* `k` tag is not required.
2023-10-11 08:55:27 -03:00
Vic
21c6c12c52 Update 57.md (#808)
Clarify how multiple relays should be included in the zap request event
2023-10-10 21:57:12 -07:00
Nostr.Band
e9f8bc27b7 add spring.site to nip-07 (#810)
Add Spring.site as NIP07 implementation
2023-10-10 14:12:21 -03:00
mattn
acbdacb625 Merge pull request #801 from badonyx/65-normalize-uri
65: Normalize relay URIs
2023-10-07 13:57:35 +09:00
Asai Toshiya
aa1bf6d268 Add NIP-24 to list 2023-10-06 08:26:02 -03:00
git
0d267aab5a Better RFC reference 2023-10-02 15:34:24 -07:00
fiatjaf
b33409c099 make it clear that relays can keep multiple replaceable event versions. 2023-09-29 16:49:55 -03:00
git
4de43f65a1 Update RFC reference 2023-09-29 12:00:07 -07:00
git
3b5d3ca677 65: normalize relay uri 2023-09-29 11:46:30 -07:00
9 changed files with 186 additions and 57 deletions

6
01.md
View File

@@ -82,12 +82,14 @@ Kinds specify how clients should interpret the meaning of each event and the oth
And also a convention for kind ranges that allow for easier experimentation and flexibility of relay implementation:
- for kind `n` such that `1000 <= n < 10000`, events are **regular**, which means they're all expected to be stored by relays.
- for kind `n` such that `10000 <= n < 20000 || n == 0 || n == 3`, events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded.
- for kind `n` such that `10000 <= n < 20000 || n == 0 || n == 3`, events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event MUST be stored by relays, older versions MAY be discarded.
- for kind `n` such that `20000 <= n < 30000`, events are **ephemeral**, which means they are not expected to be stored by relays.
- for kind `n` such that `30000 <= n < 40000`, events are **parameterized replaceable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag's first value, only the latest event is expected to be stored by relays, older versions are expected to be discarded.
- for kind `n` such that `30000 <= n < 40000`, events are **parameterized replaceable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag's first value, only the latest event MUST be stored by relays, older versions MAY be discarded.
In case of replaceable events with the same timestamp, the event with the lowest id (first in lexical order) should be retained, and the other discarded.
When answering to `REQ` messages for replaceable events such as `{"kinds":[0],"authors":[<hex-key>]}`, even if the relay has more than one version stored, it SHOULD return just the latest one.
These are just conventions and relay implementations may differ.
## Communication between clients and relays

31
03.md
View File

@@ -4,20 +4,31 @@ NIP-03
OpenTimestamps Attestations for Events
--------------------------------------
`draft` `optional` `author:fiatjaf`
`draft` `optional` `author:fiatjaf` `author:constant`
When there is an OTS available it MAY be included in the existing event body under the `ots` key:
This NIP defines an event with `kind:1040` that can contain an [OpenTimestamps](https://opentimestamps.org/) proof for any other event:
```
```json
{
"id": ...,
"kind": ...,
...,
...,
"ots": <base64-encoded OTS file data>
"kind": 1040
"tags": [
["e", <event-id>, <relay-url>],
["alt", "opentimestamps attestation"]
],
"content": <base64-encoded OTS file data>
}
```
The _event id_ MUST be used as the raw hash to be included in the OpenTimestamps merkle tree.
- The OpenTimestamps proof MUST prove the referenced `e` event id as its digest.
- The `content` MUST be the full content of an `.ots` file containing at least one Bitcoin attestation. This file SHOULD contain a **single** Bitcoin attestation and no reference to "pending" attestations since they are useless in this context.
The attestation can be either provided by relays automatically (and the OTS binary contents just appended to the events it receives) or by clients themselves when they first upload the event to relays — and used by clients to show that an event is really "at least as old as [OTS date]".
### Example OpenTimestamps proof verification flow
Using [`nak`](https://github.com/fiatjaf/nak), [`jq`](https://jqlang.github.io/jq/) and [`ots`](https://github.com/fiatjaf/ots):
```bash
~> nak req -i e71c6ea722987debdb60f81f9ea4f604b5ac0664120dd64fb9d23abc4ec7c323 wss://nostr-pub.wellorder.net | jq -r .content | ots verify
> using an esplora server at https://blockstream.info/api
- sequence ending on block 810391 is valid
timestamp validated at block [810391]
```

16
06.md
View File

@@ -13,3 +13,19 @@ Basic key derivation from mnemonic seed phrase
A basic client can simply use an `account` of `0` to derive a single key. For more advanced use-cases you can increment `account`, allowing generation of practically infinite keys from the 5-level path with hardened derivation.
Other types of clients can still get fancy and use other derivation paths for their own other purposes.
### Test vectors
mnemonic: leader monkey parrot ring guide accident before fence cannon height naive bean\
private key (hex): 7f7ff03d123792d6ac594bfa67bf6d0c0ab55b6b1fdb6249303fe861f1ccba9a\
nsec: nsec10allq0gjx7fddtzef0ax00mdps9t2kmtrldkyjfs8l5xruwvh2dq0lhhkp\
public key (hex): 17162c921dc4d2518f9a101db33695df1afb56ab82f5ff3e5da6eec3ca5cd917\
npub: npub1zutzeysacnf9rru6zqwmxd54mud0k44tst6l70ja5mhv8jjumytsd2x7nu
---
mnemonic: what bleak badge arrange retreat wolf trade produce cricket blur garlic valid proud rude strong choose busy staff weather area salt hollow arm fade\
private key (hex): c15d739894c81a2fcfd3a2df85a0d2c0dbc47a280d092799f144d73d7ae78add\
nsec: nsec1c9wh8xy5eqdzln7n5t0ctgxjcrdug73gp5yj0x03gntn67h83twssdfhel\
public key (hex): d41b22899549e1f3d335a31002cfd382174006e166d3e658e3a5eecdb6463573\
npub: npub16sdj9zv4f8sl85e45vgq9n7nsgt5qphpvmf7vk8r5hhvmdjxx4es8rq74h

1
07.md
View File

@@ -33,3 +33,4 @@ async window.nostr.nip04.decrypt(pubkey, ciphertext): string // takes ciphertext
- [AKA Profiles](https://github.com/neilck/aka-extension) (Chrome, stores multiple keys)
- [TokenPocket](https://www.tokenpocket.pro/) (Android, IOS, Chrome and derivatives)
- [Nostrmo](https://github.com/haorendashu/nostrmo_faq#download) (Android, IOS)
- [Spring Browser](https://spring.site) (Android)

6
25.md
View File

@@ -7,7 +7,7 @@ Reactions
`draft` `optional` `author:jb55`
A reaction is a `kind 7` note that is used to react to other notes.
A reaction is a `kind 7` event that is used to react to other events.
The generic reaction, represented by the `content` set to a `+` string, SHOULD
be interpreted as a "like" or "upvote".
@@ -34,6 +34,9 @@ The last `e` tag MUST be the `id` of the note that is being reacted to.
The last `p` tag MUST be the `pubkey` of the event being reacted to.
The reaction event MAY include a `k` tag with the stringified kind number
of the reacted event as its value.
Example code
```swift
@@ -43,6 +46,7 @@ func make_like_event(pubkey: String, privkey: String, liked: NostrEvent) -> Nost
}
tags.append(["e", liked.id])
tags.append(["p", liked.pubkey])
tags.append(["k", liked.kind])
let ev = NostrEvent(content: "+", pubkey: pubkey, kind: 7, tags: tags)
ev.calculate_id()
ev.sign(privkey: privkey)

90
41.md Normal file
View File

@@ -0,0 +1,90 @@
# NIP-41
## Key migration
`draft` `optional` `author:pablof7z` `author:fiatjaf` `author:nvk`
This NIP introduces a simple, best-effort, not guaranteed, way in which a user can notify their followers that they have migrated to a new public key in case the current one is compromised.
# Basic concepts
* `kind:1776` whitelists a pubkey.
* `kind:1777` migrates to a previously whitelisted pubkey.
* `kind:1776` and `kind:1777` MUST be opentimestamped [NIP-03](https://github.com/nostr-protocol/nips/blob/master/03.md).
* When a migration event is published, a 60-day period starts in which a user can publish a competing migration event pointing to an earlier `kind:1776` event. After this period, clients SHOULD automatically update the user's follow list to the new pubkey.
* Relays SHOULD NOT delete `kind:1040` nor `kind:1776` events from their database upon receiving a `kind:5` event.
# Flow
## Whitelisting a pubkey
The user's active pubkey (e.g. *pubkey A*) signs an event `kind:1776` whitelisting a pubkey that can be used to migrate an identity to.
This should be done ahead of time, perhaps after a user has used Nostr enough for a few days. Clients can choose to prompt the user to "save a recovery kit" or different UXs when they see the user doesn't currently have a `kind:1776` published.
The implementation can be done directly on regular clients or microapps to handle this type of thing could be implemented as well.
```json
{
"pubkey": "pubkey-A",
"kind": 1776,
"content": "",
"tags": [
[ "p", "pubkey-B" ],
[ "alt", "pubkey whitelisting event" ]
]
}
```
* `.content` SHOULD be ignored. Users might choose to use it to leave a base64 symmetrically-encrypted message of where they left the new key or anything else.
* The event MUST have a single `p` tag listing the whitelisted pubkey.
Multiple `kind:1776` events can exist. All `kind:1776` MUST be opentimestamped following [NIP-3](https://github.com/nostr-protocol/nips/blob/master/03.md).
Relays SHOULD NOT delete `kind:1040` nor `kind:1776` events upon receiving a `kind:5` event.
## Migrating to a pubkey
When the user needs to change keys they sign an event `kind:1777` with the new key and creates a NIP-03 attestation.
```json
{
"pubkey": "pubkey-B",
"kind": 1777,
"content": "I rolled my key using libbitcoin; moving to a new one just in case",
"tags": [
[ "p", "pubkey-A" ],
[ "e", "<kind:1776-event-id>" ],
[ "proof", "<kind:1040-event-id>" ],
[ "alt", "pubkey migration event" ],
[ "relays", "relay1", "relay2" ]
]
}
```
* `p` tag MUST list the previous pubkey
* `e` tag MUST list the `kind:1776` event that whitelisted the new pubkey.
* `proof` tag MUST list the `kind:1040` event that provides the Opentimestamp data of the `kind:1776` event.
* `relays` tag SHOULD list relays where both `kind:1776` and `kind:1040` events can be found.
* `.content` SHOULD be ignored; users can optionally write a message explaining the migration.
## Following the new pubkey
Upon seeing this event, the client MAY choose to display a warning to the user that the identity is migrating to a new key. The client should not take any automated action at this point since the migration could be an attack, but the user could communicate out of band with the user to confirm the migration.
After 60 days of seeing the `kind:1777` event, the client SHOULD automatically update the user's follow list to the new pubkey after some verifications:
When users who follow the old pubkey see a `kind:1777` event they SHOULD:
* check `kind:1776` and `kind:1777` event signatures
* check `kind:1777`'s `pubkey` matches `kind:1776`'s `p` tag
* check `kind:1777` is more than 60 days old
* check that no competing 1777 event exists pointing to an event with an older valid OTS proof
After validating all these checks clients SHOULD replace the old pubkey in the user's follow list with the new one.
## Notes
### Rational behind the 60 days delay
This gives enough time for a user to notice a migration request published by an attacker and gives the user enough time to publish a competing migration request pointing to an earlier `kind:1776` whitelisting event.
### Preventing unpublished evil `kind:1777` attack
Clients should keep track of when a `kind:1777` event should take into effect, counting at least 60 days from the time of seeing the event and not trusting the event timestamp. This is to prevent an attacker creating an evil `kind:1776`, its attestation, and a `kind:1777` event with its attestation and not publishing them until the 60 days of the attestation have elapsed.
#### Preventing poorly-distributed evil `kind:1777` attack
Additionally, clients SHOULD broadcast the `kind:1777` events to the relays it normally writes to. This is to prevent an attacker from creating a short-lived NIP-65 relay list where only a subset of users will see an evil `kind:1777` event but not widespread enough for the real owner to notice it.
### Future Work
Key migration can be done in multiple ways. This is an initial implementation that can work. This mechanism should be extended with other, alternative mechanisms, that can leverage different flows/tradeoffs (e.g. social recovery).

4
57.md
View File

@@ -45,7 +45,7 @@ Example:
"kind": 9734,
"content": "Zap!",
"tags": [
["relays", "wss://nostr-pub.wellorder.com"],
["relays", "wss://nostr-pub.wellorder.com", "wss://anotherrelay.example.com"],
["amount", "21000"],
["lnurl", "lnurl1dp68gurn8ghj7um5v93kketj9ehx2amn9uh8wetvdskkkmn0wahz7mrww4excup0dajx2mrv92x9xp"],
["p", "04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9"],
@@ -66,7 +66,7 @@ A signed `zap request` event is not published, but is instead sent using a HTTP
- `nostr` is the `9734` `zap request` event, JSON encoded then URI encoded
- `lnurl` is the lnurl pay url of the recipient, encoded using bech32 with the prefix `lnurl`
This request should return a JSON response with a `pr` key, which is the invoice the sender must pay to finalize his zap. Here is an example flow:
This request should return a JSON response with a `pr` key, which is the invoice the sender must pay to finalize his zap. Here is an example flow in javascript:
```javascript
const senderPubkey // The sender's pubkey

2
65.md
View File

@@ -60,4 +60,4 @@ This NIP allows Clients to connect directly with the most up-to-date relay set f
5. If a relay signals support for this NIP in their [NIP-11](11.md) document that means they're willing to accept kind 10002 events from a broad range of users, not only their paying customers or whitelisted group.
6. Clients SHOULD trim trailing slashes (`/`) from relay URIs to canonicalize connections.
6. Clients SHOULD deduplicate connections by normalizing relay URIs according to [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986#section-6).

View File

@@ -38,6 +38,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
- [NIP-21: `nostr:` URI scheme](21.md)
- [NIP-22: Event `created_at` Limits](22.md)
- [NIP-23: Long-form Content](23.md)
- [NIP-24: Extra metadata fields and tags](24.md)
- [NIP-25: Reactions](25.md)
- [NIP-26: Delegated Event Signing](26.md)
- [NIP-27: Text Note References](27.md)
@@ -49,6 +50,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
- [NIP-38: User Statuses](38.md)
- [NIP-39: External Identities in Profiles](39.md)
- [NIP-40: Expiration Timestamp](40.md)
- [NIP-41: Key migration](41.md)
- [NIP-42: Authentication of clients to relays](42.md)
- [NIP-45: Counting results](45.md)
- [NIP-46: Nostr Connect](46.md)
@@ -91,6 +93,9 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `44` | Channel Mute User | [28](28.md) |
| `1063` | File Metadata | [94](94.md) |
| `1311` | Live Chat Message | [53](53.md) |
| `1040` | OpenTimestamps | [03](03.md) |
| `1776` | Key Migration Whitelist | [41](41.md) |
| `1777` | Key Migration | [41](41.md) |
| `1984` | Reporting | [56](56.md) |
| `1985` | Label | [32](32.md) |
| `4550` | Community Post Approval | [72](72.md) |
@@ -155,47 +160,47 @@ Please update these lists when proposing NIPs introducing new event kinds.
## Standardized Tags
| name | value | other parameters | NIP |
| ----------------- | ------------------------------------ | -------------------- | ------------------------ |
| `e` | event id (hex) | relay URL, marker | [01](01.md), [10](10.md) |
| `p` | pubkey (hex) | relay URL, petname | [01](01.md), [02](02.md) |
| `a` | coordinates to an event | relay URL | [01](01.md) |
| `d` | identifier | -- | [01](01.md) |
| `alt` | summary | -- | [31](31.md) |
| `g` | geohash | -- | [52](52.md) |
| `i` | identity | proof | [39](39.md) |
| `k` | kind number (string) | -- | [18](18.md), [72](72.md) |
| `l` | label, label namespace | annotations | [32](32.md) |
| `L` | label namespace | -- | [32](32.md) |
| `m` | MIME type | -- | [94](94.md) |
| `r` | a reference (URL, etc) | petname | |
| `r` | relay url | marker | [65](65.md) |
| `t` | hashtag | -- | |
| `amount` | millisatoshis, stringified | -- | [57](57.md) |
| `bolt11` | `bolt11` invoice | -- | [57](57.md) |
| `challenge` | challenge string | -- | [42](42.md) |
| `content-warning` | reason | -- | [36](36.md) |
| `delegation` | pubkey, conditions, delegation token | -- | [26](26.md) |
| `description` | invoice/badge description | -- | [57](57.md), [58](58.md) |
| `emoji` | shortcode, image URL | -- | [30](30.md) |
| `expiration` | unix timestamp (string) | -- | [40](40.md) |
| `goal` | event id (hex) | relay URL | [75](75.md) |
| `image` | image URL | dimensions in pixels | [23](23.md), [58](58.md) |
| `lnurl` | `bech32` encoded `lnurl` | -- | [57](57.md) |
| `location` | location string | -- | [52](52.md), [99](99.md) |
| `name` | badge name | -- | [58](58.md) |
| `nonce` | random | -- | [13](13.md) |
| `preimage` | hash of `bolt11` invoice | -- | [57](57.md) |
| `price` | price | currency, frequency | [99](99.md) |
| `proxy` | external ID | protocol | [48](48.md) |
| `published_at` | unix timestamp (string) | -- | [23](23.md) |
| `relay` | relay url | -- | [42](42.md) |
| `relays` | relay list | -- | [57](57.md) |
| `subject` | subject | -- | [14](14.md) |
| `summary` | article summary | -- | [23](23.md) |
| `thumb` | badge thumbnail | dimensions in pixels | [58](58.md) |
| `title` | article title | -- | [23](23.md) |
| `zap` | pubkey (hex), relay URL | weight | [57](57.md) |
| name | value | other parameters | NIP |
| ----------------- | ------------------------------------ | -------------------- | ------------------------------------- |
| `e` | event id (hex) | relay URL, marker | [01](01.md), [10](10.md) |
| `p` | pubkey (hex) | relay URL, petname | [01](01.md), [02](02.md) |
| `a` | coordinates to an event | relay URL | [01](01.md) |
| `d` | identifier | -- | [01](01.md) |
| `alt` | summary | -- | [31](31.md) |
| `g` | geohash | -- | [52](52.md) |
| `i` | identity | proof | [39](39.md) |
| `k` | kind number (string) | -- | [18](18.md), [25](25.md), [72](72.md) |
| `l` | label, label namespace | annotations | [32](32.md) |
| `L` | label namespace | -- | [32](32.md) |
| `m` | MIME type | -- | [94](94.md) |
| `r` | a reference (URL, etc) | petname | |
| `r` | relay url | marker | [65](65.md) |
| `t` | hashtag | -- | |
| `amount` | millisatoshis, stringified | -- | [57](57.md) |
| `bolt11` | `bolt11` invoice | -- | [57](57.md) |
| `challenge` | challenge string | -- | [42](42.md) |
| `content-warning` | reason | -- | [36](36.md) |
| `delegation` | pubkey, conditions, delegation token | -- | [26](26.md) |
| `description` | invoice/badge description | -- | [57](57.md), [58](58.md) |
| `emoji` | shortcode, image URL | -- | [30](30.md) |
| `expiration` | unix timestamp (string) | -- | [40](40.md) |
| `goal` | event id (hex) | relay URL | [75](75.md) |
| `image` | image URL | dimensions in pixels | [23](23.md), [58](58.md) |
| `lnurl` | `bech32` encoded `lnurl` | -- | [57](57.md) |
| `location` | location string | -- | [52](52.md), [99](99.md) |
| `name` | badge name | -- | [58](58.md) |
| `nonce` | random | -- | [13](13.md) |
| `preimage` | hash of `bolt11` invoice | -- | [57](57.md) |
| `price` | price | currency, frequency | [99](99.md) |
| `proxy` | external ID | protocol | [48](48.md) |
| `published_at` | unix timestamp (string) | -- | [23](23.md) |
| `relay` | relay url | -- | [42](42.md) |
| `relays` | relay list | -- | [57](57.md) |
| `subject` | subject | -- | [14](14.md) |
| `summary` | article summary | -- | [23](23.md) |
| `thumb` | badge thumbnail | dimensions in pixels | [58](58.md) |
| `title` | article title | -- | [23](23.md) |
| `zap` | pubkey (hex), relay URL | weight | [57](57.md) |
## Criteria for acceptance of NIPs