Compare commits
8 Commits
fc08866368
...
9be64e36a0
Author | SHA1 | Date |
---|---|---|
|
9be64e36a0 | |
|
7dec812f99 | |
|
739f3c5263 | |
|
8830525250 | |
|
b224b0ecb8 | |
|
ce130e504a | |
|
0b45265a93 | |
|
063b1ffca8 |
4
03.md
4
03.md
|
@ -12,8 +12,8 @@ This NIP defines an event with `kind:1040` that can contain an [OpenTimestamps](
|
|||
{
|
||||
"kind": 1040
|
||||
"tags": [
|
||||
["e", <event-id>, <relay-url>],
|
||||
["alt", "opentimestamps attestation"]
|
||||
["e", <target-event-id>, <relay-url>],
|
||||
["k", "<target-event-kind>"]
|
||||
],
|
||||
"content": <base64-encoded OTS file data>
|
||||
}
|
||||
|
|
3
18.md
3
18.md
|
@ -40,6 +40,5 @@ Since `kind 6` reposts are reserved for `kind 1` contents, we use `kind 16`
|
|||
as a "generic repost", that can include any kind of event inside other than
|
||||
`kind 1`.
|
||||
|
||||
`kind 16` reposts SHOULD contain a `k` tag with the stringified kind number
|
||||
`kind 16` reposts SHOULD contain a `"k"` tag with the stringified kind number
|
||||
of the reposted event as its value.
|
||||
|
||||
|
|
2
21.md
2
21.md
|
@ -21,7 +21,7 @@ The identifiers that come after are expected to be the same as those defined in
|
|||
|
||||
### Linking HTML pages to Nostr entities
|
||||
|
||||
`<link>` tags with `rel="alternate"` can be used to associate webpages to Nostr events, in cases where the same content is served via the two mediums (for example, a web server that exposes Markdown articles both as HTML pages and as `kind:30023' events served under itself as a relay or through some other relay). For example:
|
||||
`<link>` tags with `rel="alternate"` can be used to associate webpages to Nostr events, in cases where the same content is served via the two mediums (for example, a web server that exposes Markdown articles both as HTML pages and as `kind:30023` events served under itself as a relay or through some other relay). For example:
|
||||
|
||||
```
|
||||
<head>
|
||||
|
|
8
22.md
8
22.md
|
@ -143,13 +143,13 @@ A comment on a website's url looks like this:
|
|||
"tags": [
|
||||
// referencing the root url
|
||||
["I", "https://abc.com/articles/1"],
|
||||
// the root "kind": for an url, the kind is its domain
|
||||
["K", "https://abc.com"],
|
||||
// the root "kind": for an url
|
||||
["K", "web"],
|
||||
|
||||
// the parent reference (same as root for top-level comments)
|
||||
["i", "https://abc.com/articles/1"],
|
||||
// the parent "kind": for an url, the kind is its domain
|
||||
["k", "https://abc.com"]
|
||||
// the parent "kind": for an url
|
||||
["k", "web"]
|
||||
]
|
||||
// other fields
|
||||
}
|
||||
|
|
13
24.md
13
24.md
|
@ -8,8 +8,7 @@ Extra metadata fields and tags
|
|||
|
||||
This NIP keeps track of extra optional fields that can added to events which are not defined anywhere else but have become _de facto_ standards and other minor implementation possibilities that do not deserve their own NIP and do not have a place in other NIPs.
|
||||
|
||||
kind 0
|
||||
======
|
||||
### kind 0
|
||||
|
||||
These are extra fields not specified in NIP-01 that may be present in the stringified JSON of metadata events:
|
||||
|
||||
|
@ -19,24 +18,22 @@ These are extra fields not specified in NIP-01 that may be present in the string
|
|||
- `bot`: a boolean to clarify that the content is entirely or partially the result of automation, such as with chatbots or newsfeeds.
|
||||
- `birthday`: an object representing the author's birth date. The format is { "year": number, "month": number, "day": number }. Each field MAY be omitted.
|
||||
|
||||
### Deprecated fields
|
||||
#### Deprecated fields
|
||||
|
||||
These are fields that should be ignored or removed when found in the wild:
|
||||
|
||||
- `displayName`: use `display_name` instead.
|
||||
- `username`: use `name` instead.
|
||||
|
||||
kind 3
|
||||
======
|
||||
### kind 3
|
||||
|
||||
These are extra fields not specified in NIP-02 that may be present in the stringified JSON of follow events:
|
||||
|
||||
### Deprecated fields
|
||||
#### Deprecated fields
|
||||
|
||||
- `{<relay-url>: {"read": <true|false>, "write": <true|false>}, ...}`: an object of relays used by a user to read/write. [NIP-65](65.md) should be used instead.
|
||||
|
||||
tags
|
||||
====
|
||||
### tags
|
||||
|
||||
These tags may be present in multiple event kinds. Whenever a different meaning is not specified by some more specific NIP, they have the following meanings:
|
||||
|
||||
|
|
9
52.md
9
52.md
|
@ -25,6 +25,7 @@ These tags are common to both types of calendar events:
|
|||
* `p` (optional, repeated) 32-bytes hex pubkey of a participant, optional recommended relay URL, and participant's role in the meeting
|
||||
* `t` (optional, repeated) hashtag to categorize calendar event
|
||||
* `r` (optional, repeated) references / links to web pages, documents, video calls, recorded videos, etc.
|
||||
* `a` (repeated) reference tag to kind `31924` calendar event requesting to be included in Calendar
|
||||
|
||||
The following tags are deprecated:
|
||||
|
||||
|
@ -32,6 +33,12 @@ The following tags are deprecated:
|
|||
|
||||
Calendar events are _not_ required to be part of a [calendar](#calendar).
|
||||
|
||||
## Collaborative Calendar Event Requests
|
||||
|
||||
Calendar events can include an `a` tag referencing a calendar (kind 31924) to request addition to that calendar. When a calendar event includes such a reference, clients should interpret this as a request to add the event to the referenced calendar by referencing it with an `a` tag.
|
||||
|
||||
This enables collaborative calendar management where multiple users can contribute events to calendars they do not own, subject to the calendar owner's approval.
|
||||
|
||||
### Date-Based Calendar Event
|
||||
|
||||
This kind of calendar event starts on a date and ends before a different date in the future. Its use is appropriate for all-day or multi-day events where time and time zone hold no significance. e.g., anniversary, public holidays, vacation days.
|
||||
|
@ -125,6 +132,8 @@ Aside from the common tags, this also takes the following tags:
|
|||
|
||||
A calendar is a collection of calendar events, represented as a custom _addressable list_ event using kind `31924`. A user can have multiple calendars. One may create a calendar to segment calendar events for specific purposes. e.g., personal, work, travel, meetups, and conferences.
|
||||
|
||||
Calendars can accept event requests from other users. When calendar events reference a calendar via an `a` tag, this represents a request for inclusion.
|
||||
|
||||
The `.content` of these events should be a detailed description of the calendar. It is required but can be an empty string.
|
||||
|
||||
* `d` (required) universally unique identifier. Generated by the client creating the calendar.
|
||||
|
|
5
57.md
5
57.md
|
@ -37,6 +37,7 @@ In addition, the event MAY include the following tags:
|
|||
|
||||
- `e` is an optional hex-encoded event id. Clients MUST include this if zapping an event rather than a person.
|
||||
- `a` is an optional event coordinate that allows tipping addressable events such as NIP-23 long-form notes.
|
||||
- `k` is the stringified kind of the target event.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -49,7 +50,8 @@ Example:
|
|||
["amount", "21000"],
|
||||
["lnurl", "lnurl1dp68gurn8ghj7um5v93kketj9ehx2amn9uh8wetvdskkkmn0wahz7mrww4excup0dajx2mrv92x9xp"],
|
||||
["p", "04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9"],
|
||||
["e", "9ae37aa68f48645127299e9453eb5d908a0cbb6058ff340d528ed4d37c8994fb"]
|
||||
["e", "9ae37aa68f48645127299e9453eb5d908a0cbb6058ff340d528ed4d37c8994fb"],
|
||||
["k", "1"]
|
||||
],
|
||||
"pubkey": "97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322",
|
||||
"created_at": 1679673265,
|
||||
|
@ -151,6 +153,7 @@ Example `zap receipt`:
|
|||
["p", "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"],
|
||||
["P", "97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322"],
|
||||
["e", "3624762a1274dd9636e0c552b53086d70bc88c165bc4dc0f9e836a1eaf86c3b8"],
|
||||
["k", "1"],
|
||||
["bolt11", "lnbc10u1p3unwfusp5t9r3yymhpfqculx78u027lxspgxcr2n2987mx2j55nnfs95nxnzqpp5jmrh92pfld78spqs78v9euf2385t83uvpwk9ldrlvf6ch7tpascqhp5zvkrmemgth3tufcvflmzjzfvjt023nazlhljz2n9hattj4f8jq8qxqyjw5qcqpjrzjqtc4fc44feggv7065fqe5m4ytjarg3repr5j9el35xhmtfexc42yczarjuqqfzqqqqqqqqlgqqqqqqgq9q9qxpqysgq079nkq507a5tw7xgttmj4u990j7wfggtrasah5gd4ywfr2pjcn29383tphp4t48gquelz9z78p4cq7ml3nrrphw5w6eckhjwmhezhnqpy6gyf0"],
|
||||
["description", "{\"pubkey\":\"97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322\",\"content\":\"\",\"id\":\"d9cc14d50fcb8c27539aacf776882942c1a11ea4472f8cdec1dea82fab66279d\",\"created_at\":1674164539,\"sig\":\"77127f636577e9029276be060332ea565deaf89ff215a494ccff16ae3f757065e2bc59b2e8c113dd407917a010b3abd36c8d7ad84c0e3ab7dab3a0b0caa9835d\",\"kind\":9734,\"tags\":[[\"e\",\"3624762a1274dd9636e0c552b53086d70bc88c165bc4dc0f9e836a1eaf86c3b8\"],[\"p\",\"32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245\"],[\"relays\",\"wss://relay.damus.io\",\"wss://nostr-relay.wlvs.space\",\"wss://nostr.fmt.wiz.biz\",\"wss://relay.nostr.bg\",\"wss://nostr.oxtr.dev\",\"wss://nostr.v0l.io\",\"wss://brb.io\",\"wss://nostr.bitcoiner.social\",\"ws://monad.jb55.com:8080\",\"wss://relay.snort.social\"]]}"],
|
||||
["preimage", "5d006d2cf1e73c7148e7519a4c68adc81642ce0e25a432b2434c99f97344c15f"]
|
||||
|
|
1
61.md
1
61.md
|
@ -53,6 +53,7 @@ Clients MUST prefix the public key they P2PK-lock with `"02"` (for nostr<>cashu
|
|||
[ "proof", "{\"amount\":1,\"C\":\"02277c66191736eb72fce9d975d08e3191f8f96afb73ab1eec37e4465683066d3f\",\"id\":\"000a93d6f8a1d2c4\",\"secret\":\"[\\\"P2PK\\\",{\\\"nonce\\\":\\\"b00bdd0467b0090a25bdf2d2f0d45ac4e355c482c1418350f273a04fedaaee83\\\",\\\"data\\\":\\\"02eaee8939e3565e48cc62967e2fde9d8e2a4b3ec0081f29eceff5c64ef10ac1ed\\\"}]\"}" ],
|
||||
[ "u", "https://stablenut.umint.cash" ],
|
||||
[ "e", "<nutzapped-event-id>", "<relay-hint>" ],
|
||||
[ "k", "<nutzapped-kind>"],
|
||||
[ "p", "e9fbced3a42dcf551486650cc752ab354347dd413b307484e4fd1818ab53f991" ], // recipient of nutzap
|
||||
]
|
||||
}
|
||||
|
|
225
66.md
225
66.md
|
@ -6,137 +6,46 @@ Relay Discovery and Liveness Monitoring
|
|||
|
||||
`draft` `optional`
|
||||
|
||||
You want to find relays. You may want to discover relays based on criteria that's up to date. You may even want to ensure that you have a complete dataset. You probably want to filter relays based on their reported liveness.
|
||||
This NIP defines events for relay discovery and the announcement of relay monitors.
|
||||
|
||||
In its purest form:
|
||||
## Relay Discovery Events
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 30166,
|
||||
"created_at": 1722173222,
|
||||
"content": "{}",
|
||||
"tags": [
|
||||
[ "d", "wss://somerelay.abc/" ]
|
||||
],
|
||||
"pubkey": "<pubkey>",
|
||||
"sig": "<signature>",
|
||||
"id": "<eventid>"
|
||||
}
|
||||
```
|
||||
`30166` relay discovery events document relay characteristics inferred either from a relay's [NIP 11](https://github.com/nostr-protocol/nips/blob/master/11.md) document, or via probing.
|
||||
|
||||
This event signals that the relay at `wss://somerelay.abc/` was reported "online" by `<pubkey>` at timestamp `1722173222`. This event **MAY** be extended upon to include more information.
|
||||
Information corresponding to field in a relay's NIP 11 document MAY contradict actual values if monitors find that a different policy is implemented than is advertised.
|
||||
|
||||
## Kinds
|
||||
`NIP-66` defines two (2) event kinds, `30166` and `10166`
|
||||
`content` MAY include the stringified JSON of the relay's NIP-11 informational document.
|
||||
|
||||
| kind | name | description |
|
||||
|-------|----------------------------|-----------------------------------------------------------------------------------------|
|
||||
| [30166](#k30166) | Relay Discovery | An addressable event that is published by a monitor when a relay is online |
|
||||
| [10166](#k10166) | Relay Monitor Announcement | An RE that stores data that signals the intent of a pubkey to monitor relays and publish `30166` events at a regular _frequency_ |
|
||||
The only required tag is the `d` tag, which MUST be set to the relay's [normalized](https://datatracker.ietf.org/doc/html/rfc3986#section-6) URL. For relays not accessible via URL, a hex-encoded pubkey MAY be used instead.
|
||||
|
||||
## Ontology
|
||||
- `Relay Operator`: someone who operates a relay
|
||||
- `Monitor`: A pubkey that monitors relays and publishes `30166` events at the frequency specified in their `10166` event.
|
||||
- `Ad-hoc Monitor`: A pubkey that monitors relays and publishes `30166` events at an irregular frequency.
|
||||
- `Monitor Service`: A group or individual that monitors relays using one or more `Monitors`.
|
||||
- `Check`: a specific data point that is tested or aggregated by a monitor.
|
||||
Other tags include:
|
||||
|
||||
## `30166`: "Relay Discovery" <a id="k30166"></a>
|
||||
- `rtt-open` - The relay's open round-trip time in milliseconds.
|
||||
- `rtt-read` - The relay's read round-trip time in milliseconds.
|
||||
- `rtt-write` - The relay's write round-trip time in milliseconds.
|
||||
- `n` - The relay's network type. SHOULD be one of `clearnet`, `tor`, `i2p`, `loki`
|
||||
- `T` - The relay type. Enumerated [relay type](https://github.com/nostr-protocol/nips/issues/1282) formatted as `PascalCase`, e.g. `PrivateInbox`
|
||||
- `N` - NIPs supported by the relay
|
||||
- `R` - Keys corresponding to requirements per [NIP 11](https://github.com/nostr-protocol/nips/blob/master/11.md)'s `limitations` array, including `auth`, `writes`, `pow`, and `payment`. False values should be specified using a `!` prefix, for example `!auth`.
|
||||
- `t` - A topic associated with this relay
|
||||
- `k` - An event kind accepted by the relay
|
||||
- `!k` - An event kind not accepted by the relay
|
||||
- `g` - A [NIP-52](https://github.com/nostr-protocol/nips/blob/master/52.md) geohash
|
||||
- `l` - A language tag
|
||||
|
||||
### Summary
|
||||
`30166` is a `NIP-33` addressable event, referred to as a "Relay Discovery" event. These events are optimized with a small footprint for protocol-level relay Discovery.
|
||||
Tags with more than one value should be repeated, rather than putting all values in a single tag, for example `[["t", "cats"], ["t", "dogs"]]`, rather than `[["t", "cats", "dogs"]]`.
|
||||
|
||||
### Purpose
|
||||
Discovery of relays over nostr.
|
||||
Example:
|
||||
|
||||
### Schema
|
||||
|
||||
#### Content
|
||||
`30166` content fields **SHOULD** include the stringified JSON of the relay's NIP-11 informational document. This data **MAY** be provided for informational purposes only.
|
||||
|
||||
#### `created_at`
|
||||
The `created_at` field in a NIP-66 event should reflect the time when the relay liveness (and potentially other data points) was checked.
|
||||
|
||||
#### `tags`
|
||||
|
||||
##### Meta Tags (unindexed)
|
||||
- `rtt-open` The relay's open **round-trip time** in milliseconds.
|
||||
- `rtt-read` The relay's read **round-trip time** in milliseconds.
|
||||
- `rtt-write` The relay's write **round-trip time** in milliseconds.
|
||||
|
||||
_Other `rtt` values **MAY** be present. This NIP should be updated if there is value found in more `rtt` values._
|
||||
|
||||
##### Single Letter Tags (indexed)
|
||||
- `d` The relay URL/URI. The `#d` tag **must** be included in the `event.tags[]` array. Index position `1` **must** be the relay websocket URL/URI. If a URL it **SHOULD** be [normalized](https://datatracker.ietf.org/doc/html/rfc3986#section-6). For relays not accessible via conventional means but rather by an npub/pubkey, an npub/pubkey **MAY** be used in place of a URL.
|
||||
```json
|
||||
[ "d", "wss://somerelay.abc/"]
|
||||
```
|
||||
|
||||
- `n`: Network
|
||||
```json
|
||||
[ "n", "clearnet" ]
|
||||
```
|
||||
|
||||
- `T`: Relay Type. Enumerated [relay type](https://github.com/nostr-protocol/nips/issues/1282) formatted as `PascalCase`
|
||||
```json
|
||||
["T", "PrivateInbox" ]
|
||||
```
|
||||
|
||||
- `N`: Supported Nips _From NIP-11 "Informational Document" `nip11.supported_nips[]`_
|
||||
```json
|
||||
[ "N", "42" ]
|
||||
```
|
||||
|
||||
- `R`: Requirements _NIP-11 "Informational Document" `nip11.limitations.payment_required`, `nip11.limitations.auth_required` and/or any other boolean value within `nip11.limitations[]` that is added in the future_
|
||||
```json
|
||||
[ "R", "payment" ],
|
||||
[ "R", "auth" ],
|
||||
```
|
||||
Since the nostr protocol does not currently support filtering on whether an indexed tag **is** or **is not** set, to make "public" and "no auth" relays discoverable requires a `!` flag
|
||||
|
||||
```json
|
||||
[ "R", "!payment" ], //no payment required, is public
|
||||
[ "R", "!auth" ], //no authentication required
|
||||
```
|
||||
|
||||
- `t`: "Topics" _From NIP-11 "Informational Document" `nip11.tags[]`_
|
||||
```json
|
||||
[ "t", "nsfw" ]
|
||||
```
|
||||
|
||||
- `k`: Accepted/Blocked Kinds [`NIP-22`]
|
||||
```json
|
||||
[ "k", "0" ],
|
||||
[ "k", "3" ],
|
||||
[ "k", "10002" ]
|
||||
```
|
||||
|
||||
or for blocked kinds
|
||||
|
||||
```json
|
||||
[ "k", "!0" ]
|
||||
[ "k", "!3" ],
|
||||
[ "k", "!10002" ]
|
||||
```
|
||||
|
||||
- `g`: `NIP-52` `g` tags (geohash)
|
||||
```json
|
||||
[ "g", "9r1652whz" ]
|
||||
```
|
||||
|
||||
- `30166` **MAY** be extended with global tags defined by other NIPs that do no collide with locally defined indices, including but not limited to: `p`, `t`, `e`, `a`, `i` and `l/L`.
|
||||
|
||||
#### Robust Example of a `30166` Event
|
||||
_Relay was online, and you can filter on a number of different tags_
|
||||
```json
|
||||
{
|
||||
"id": "<eventid>",
|
||||
"pubkey": "<monitor's pubkey>",
|
||||
"created_at": "<created_at [some recent date ...]>",
|
||||
"signature": "<signature>",
|
||||
"content": "{}",
|
||||
"content": "<optional nip 11 document>",
|
||||
"kind": 30166,
|
||||
"tags": [
|
||||
"tags": [
|
||||
["d","wss://some.relay/"],
|
||||
["n", "clearnet"],
|
||||
["N", "40"],
|
||||
|
@ -144,64 +53,28 @@ _Relay was online, and you can filter on a number of different tags_
|
|||
["R", "!payment"],
|
||||
["R", "auth"],
|
||||
["g", "ww8p1r4t8"],
|
||||
["p", "somehexkey..."],
|
||||
["l", "en", "ISO-639-1"],
|
||||
["t", "nsfw" ],
|
||||
["rtt-open", 234 ]
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## `10166`: "Relay Monitor Announcement" Events <a id="k10166"></a>
|
||||
## Relay Monitor Announcements
|
||||
|
||||
### Summary
|
||||
`10166` is a replacable event herein referred to as "Relay Monitor Announcement" events. These events contain information about a publisher's intent to monitor and publish data as `30166` events. This event is optional and is intended for monitors who intend to provide monitoring services at a regular and predictable frequency.
|
||||
Kind `10166` relay monitor announcements advertise the author's intent to publish `30166` events. This event is optional and is intended for monitors who intend to provide monitoring services at a regular and predictable frequency.
|
||||
|
||||
### Purpose
|
||||
To provide a directory of monitors, their intent to publish, their criteria and parameters of monitoring activities. Absence of this event implies the monitor is ad-hoc and does not publish events at a predictable frequency, and relies on mechanisms to infer data integrity, such as web-of-trust.
|
||||
Tags include:
|
||||
|
||||
### Schema
|
||||
- `frequency` - The frequency in seconds at which the monitor publishes events.
|
||||
- `timeout` (optional) - The timeout values for various checks conducted by a monitor. Index `1` is the monitor's timeout in milliseconds. Index `2` describes what test the timeout is used for. If no index `2` is provided, it is inferred that the timeout provided applies to all tests.
|
||||
- `c` - a lowercase string describing the checks conducted by a monitor. Examples include `open`, `read`, `write`, `auth`, `nip11`, `dns`, and `geo`.
|
||||
- `g` - [NIP-52](https://github.com/nostr-protocol/nips/blob/master/11.md) geohash tag
|
||||
|
||||
#### Standard Tags
|
||||
Monitors SHOULD also publish a `kind 0` profile and a `kind 10002` relay selections event.
|
||||
|
||||
- `frequency` The frequency **in seconds** at which the monitor publishes events. A string-integer at index `1` represents the expected frequency the monitor will publish `30166` events. There should only be `1` frequency per monitor.
|
||||
Example:
|
||||
|
||||
```json
|
||||
[ "frequency", "3600" ]
|
||||
```
|
||||
|
||||
- `timeout` (optional) The timeout values for various checks conducted by a monitor. Index `1` is the monitor's timeout in milliseconds. Index `2` describes what test the timeout is used for. If no index `2` is provided, it is inferred that the timeout provided applies to all tests. These values can assist relay operators in understanding data signaled by the monitor in _Relay Discovery Events_.
|
||||
```json
|
||||
[ "timeout", "2000", "open" ],
|
||||
[ "timeout", "2000", "read" ],
|
||||
[ "timeout", "3000", "write" ],
|
||||
[ "timeout", "2000", "nip11" ],
|
||||
[ "timeout", "4000", "ssl" ]
|
||||
```
|
||||
|
||||
#### Indexed Tags
|
||||
- `c` "Checks" **SHOULD** be a lowercase string describing the check(s) conducted by a monitor. Due to the rapidly evolving nature of relays, enumeration is organic and not strictly defined. But examples of some checks could be websocket `open/read/write/auth`, `nip11` checks, `dns` and `geo` checks, and and any other checks the monitor may deem useful.. Other checks **MAY** be included. New types of checks **SHOULD** be added to this NIP as they are needed.
|
||||
```json
|
||||
[ "c", "ws" ],
|
||||
[ "c", "nip11" ],
|
||||
[ "c", "dns" ],
|
||||
[ "c", "geo" ],
|
||||
[ "c", "ssl" ],
|
||||
```
|
||||
|
||||
- `g`: `NIP-52` `g` tags (geohash)
|
||||
```json
|
||||
[ "g", "9r1652whz" ]
|
||||
```
|
||||
|
||||
- Any other globally defined indexable tags **MAY** be included as found necessary.
|
||||
|
||||
### Other Requirements
|
||||
Monitors **SHOULD** have the following
|
||||
- A published `0` (NIP-1) event
|
||||
- A published `10002` (NIP-65) event that defines the relays the monitor publishes to.
|
||||
|
||||
### Robust Example of a `10166` Event
|
||||
```json
|
||||
{
|
||||
"id": "<eventid>",
|
||||
|
@ -209,46 +82,18 @@ Monitors **SHOULD** have the following
|
|||
"created_at": "<created_at [some recent date ...]>",
|
||||
"signature": "<signature>",
|
||||
"content": "",
|
||||
"tags": [
|
||||
|
||||
"tags": [
|
||||
[ "timeout", "open", "5000" ],
|
||||
[ "timeout", "read", "3000" ],
|
||||
[ "timeout", "write", "3000" ],
|
||||
[ "timeout", "nip11", "3000" ],
|
||||
|
||||
[ "frequency", "3600" ],
|
||||
|
||||
[ "c", "ws" ],
|
||||
[ "c", "nip11" ],
|
||||
[ "c", "ssl" ],
|
||||
[ "c", "dns" ],
|
||||
[ "c", "geo" ]
|
||||
|
||||
[ "g", "ww8p1r4t8" ]
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Methodology
|
||||
|
||||
### Monitors
|
||||
1. A _Relay Monitor_ checks the liveness and potentially other attributes of a relay.
|
||||
|
||||
2. _Relay Monitor_ publishes a kind `30166` note when a relay it is monitoring is online. If the monitor has a `10166` event, events should be published at the frequency defined in their `10166` note.
|
||||
|
||||
_Any pubkey that publishes `30166` events **SHOULD** at a minimum be checking that the relay is available by websocket and behaves like a relay_
|
||||
|
||||
### Clients
|
||||
1. In most cases, a client **SHOULD** filter on `30166` events using either a statically or dynamically defined monitor's `pubkey` and a `created_at` value respective of the monitor's published `frequency`. If the monitor has no stated frequency, other mechanisms should be employed to determine data integrity.
|
||||
|
||||
2. _Relay Liveness_ is subjectively determined by the client, starting with the `frequency` value of a monitor.
|
||||
|
||||
3. The liveness of a _Relay Monitor_ can be subjectively determined by detecting whether the _Relay Monitor_ has published events with respect to `frequency` value of any particular monitor.
|
||||
|
||||
4. The reliability and trustworthiness of a _Relay Monitor_ could be established via web-of-trust, reviews or similar mechanisms.
|
||||
|
||||
## Risk Mitigation
|
||||
|
||||
- When a client implements `NIP-66` events, the client should have a fallback if `NIP-66` events cannot be located.
|
||||
|
||||
- A `Monitor` or `Ad-hoc Monitor` may publish erroneous `30166` events, intentionally or otherwise. Therefor, it's important to program defensively to limit the impact of such events. This can be achieved with web-of-trust, reviews, fallbacks and/or data-aggregation for example.
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
NIP-X
|
||||
=====
|
||||
|
||||
Bare Signatures
|
||||
------
|
||||
|
||||
Under certain circumstances you may wish to sign content that isn't a well formed nostr message. Perhaps something like:
|
||||
|
||||
```
|
||||
jack @jack
|
||||
We reject: kings, presidents, and voting.
|
||||
We believe in: rough consensus and running code.
|
||||
|
||||
—David Clark, 1992
|
||||
|
||||
3:31 PM · Sep 11, 2024 · 661.6K Views [https://x.com/jack/status/1833951636005552366]
|
||||
```
|
||||
|
||||
If this was posted to Nostr it would be trivial to verify whether it was signed using the expected private key. If was not, we have to evaluate how likely it is to be true. How was it was published? Does it sound like something the author would say? Was it said at a time the author would have said it? Has it remained unchanged since it was published? If the platform were sold, do we trust the new ownership? If it closed, do we have recordings of it that we trust? Without a cryptographic signature, the truth is mostly conjecture.
|
||||
|
||||
## What's In a Signature?
|
||||
|
||||
In nostr messages are signed by collecting pertinent details, arranging them in a rigid manner, taking a hash, and signing the hash. For the above, the input might look like:
|
||||
|
||||
```json
|
||||
{
|
||||
"pubkey": "82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2",
|
||||
"created_at": 1726083060001,
|
||||
"kind": 1,
|
||||
"tags": [],
|
||||
"content": "We reject: kings, presidents, and voting.\nWe believe in: rough consensus and running code.\n\n—David Clark, 1992"
|
||||
}
|
||||
```
|
||||
|
||||
Wait a second, where did all of that come from? Well, the author has included an npub on their profile page, so that's a good place to start. Then, the event does have a relatively narrow timestamp, down to the minute. Most of these types of messages are "kind":1 on nostr, and we'll just assume that there aren't any fancy tags.
|
||||
|
||||
Having roughly constructed a plausible event, we can now generate an `id` for it, and finally check that the signature is valid. Except: we don't have the signature, and we kind-of just made up the timestamp. If we actually had a signature the timestamp would be kind of easy: just try all of them for the expected time period – it's really fast. So now all we need is the signature.
|
||||
|
||||
An event signature is pretty long. Here's an example:
|
||||
|
||||
```
|
||||
3046022100dc07c1e346d41605a555688e65fb08496e657ebf23421045f65413703e37259c0221009045ebd40430ad2a7aaa73ae20b350a0113b3cda6446887e6ded7e5e6af2929a
|
||||
```
|
||||
|
||||
Given message length constraints on certain systems, including 144 meaningless characters is really going to cramp your style. What IS the limit on those other systems, though? Is it really 180 characters? Well, it depends on how many bytes you think a character is.
|
||||
|
||||
## Base8196
|
||||
|
||||
The limit is actually 180 things-that-look-like-characters, which happens to include Hangul syllables. The unicode standard includes a commonly implemented (block)[https://en.wikipedia.org/wiki/Hangul_Syllables] for these, giving us easily pasteable access to 11,172 characters per character. That's even more than we need, so we can throw out some of the more archaic glyphs and still have plenty for 13 bits per character. With this encoding the above signature is now 45 characters:
|
||||
|
||||
```
|
||||
됀쯾쇼빠삷촙쨶쥕잚죔떔홈숎탟믟햗뛲굟퀶궋겚빩봢껍값굟줴걕궴먨졳와녨붢셠왅츾쵫웹풕펡췱좟렱욤
|
||||
```
|
||||
|
||||
leaving you with at least 135 characters to change the world. Having supplied a simple message and signature, it's now possible for us to fully reconstruct the above event, possibly by burning through every `created_at` in a week until we find the number that produces a valid signature.
|
||||
|
||||
## But Why
|
||||
|
||||
Assuming that you've gone through the trouble to say something important in the first place, and you have the private key necessary to produce a valid signature, why wouldn't you just post to nostr? That's a good question, but why are you raining on this awesome parade, and actually I also wish that I knew the answer but here we are.
|
||||
|
||||
Assuming that someone has posted an interesting message that either included a signature or was in close proximity to another message that contained a signature... why would anyone care? This is an even more exciting question because it reveals what it means to publish to nostr - that is, to Sign Things and Relay Them.
|
||||
|
||||
Once you have signed an event, it has been published. You may have also sent it to your relays, but you could be offline. You might wrap its delivery in Tor, or yeeted it to every plaintext relay you could find. (My kids are expanding my vocabulary.) Maybe only the NSA has a copy, or there's a polaroid someone took of you while it was on your screen. Once you have signed it it has been published because anyone who manages to obtain the information in that event along with the signature, can publish it to whatever relays they want. Yes, you can publish events over instant film. Or Ham radio. Or QR code. Or peer to peer onion service.
|
||||
|
||||
And once that happens, it isn't people talking about what you may have said... it is literally what you said. It has your profile photo, your followers get alerts, you would get reply notifications if you ever logged in, yadda yadda.
|
||||
|
||||
And so, I propose an informal standard for signing plain text. It doesn't need to use anything exotic like my so very clever base8196, you just need to sign an event with nothing in it except for the content, and then share both the content and the signature.
|
||||
|
||||
Did you know that Hangul is phoenetic?
|
||||
|
||||
## One implementation of Base8196
|
||||
|
||||
```python
|
||||
INITIAL_CONSONANTS = 'ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ'
|
||||
VOWELS = 'ㅏㅐㅑㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ'
|
||||
FINAL_CONSONANTS = 'ㄱㄲㄳㄴㄵㄶㄷㄹㄺㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ'
|
||||
|
||||
TOKENS = [chr(0xAC00 + (588 * ci) + (28 * vi) + fi)
|
||||
for ci, c in enumerate(INITIAL_CONSONANTS)
|
||||
for vi, v in enumerate(VOWELS)
|
||||
for fi, f in enumerate([''] + list(FINAL_CONSONANTS))]
|
||||
|
||||
def base8192_encode(data):
|
||||
result = []
|
||||
bits = ''.join(format(byte, '08b') for byte in data)
|
||||
for i in range(0, len(bits), 13):
|
||||
chunk = bits[i:i+13]
|
||||
if len(chunk) < 13:
|
||||
chunk = chunk.ljust(13, '0')
|
||||
index = int(chunk, 2)
|
||||
result.append(TOKENS[index])
|
||||
return ''.join(result)
|
||||
|
||||
def base8192_decode(encoded):
|
||||
bits = ''
|
||||
for char in encoded:
|
||||
index = TOKENS.index(char)
|
||||
bits += format(index, '013b')
|
||||
result = bytes(int(bits[i:i+8], 2) for i in range(0, len(bits), 8))
|
||||
while result[-1] == 0:
|
||||
result = result[:-1]
|
||||
return result
|
||||
```
|
Loading…
Reference in New Issue