{"id":"09136ce0a35c2c1922480532f924d4875f42af3f6f29298f20de321cd6ef3dd3","pubkey":"daa41bedb68591363bf4407f687cb9789cc543ed024bb77c22d2c84d88f54153","created_at":1768620194,"kind":30817,"tags":[["d","trusted-relay-assertions"],["title","Trusted Relay Assertions"],["client","nostrhub.io"]],"content":"# NIP-XX: Trusted Relay Assertions\n\n`draft` `optional`\n\nThis NIP defines a standard for publishing trust assertions about Nostr relays. Assertion providers compute trust scores from observed metrics (NIP-66), operator reputation, and user reports. Clients query these assertions to make informed relay connection decisions.\n\n## Relationship to Other NIPs\n\n| NIP | Role |\n|-----|------|\n| NIP-11 | What relay *claims* (self-description) |\n| NIP-66 | What we *measured* (observed metrics) |\n| NIP-XX | What we *conclude* (trust evaluation) |\n\nProviders SHOULD consume NIP-66 data to compute scores. This NIP adds the trust layer.\n\n## Assertion Events\n\n### Kind 30385: Trusted Relay Assertion\n\nA parameterized replaceable event with `d` tag containing the relay's canonical WebSocket URL (lowercase, no trailing slash).\n\n```json\n{\n  \"kind\": 30385,\n  \"pubkey\": \"<provider_pubkey>\",\n  \"created_at\": 1704067200,\n  \"tags\": [\n    [\"d\", \"wss://relay.example.com\"],\n    [\"status\", \"evaluated\"],\n    [\"algorithm\", \"v0.1\"],\n    [\"algorithm_url\", \"https://trustedrelays.xyz/ALGORITHM.md\"],\n    [\"score\", \"82\"],\n    [\"reliability\", \"94\"],\n    [\"quality\", \"76\"],\n    [\"accessibility\", \"81\"],\n    [\"confidence\", \"high\"],\n    [\"observations\", \"12450\"],\n    [\"observation_period\", \"30d\"],\n    [\"first_seen\", \"1640000000\"],\n    [\"operator\", \"<operator_pubkey>\"],\n    [\"operator_verified\", \"nip11\"],\n    [\"operator_confidence\", \"70\"],\n    [\"operator_trust\", \"88\"],\n    [\"policy\", \"moderated\"],\n    [\"policy_confidence\", \"85\"],\n    [\"country_code\", \"DE\"],\n    [\"region\", \"Bavaria\"],\n    [\"is_hosting\", \"true\"]\n  ],\n  \"content\": \"\"\n}\n```\n\n### Required Tags\n\n| Tag | Format | Description |\n|-----|--------|-------------|\n| `d` | `wss://...` | Relay WebSocket URL |\n| `status` | string | `evaluated`, `insufficient_data`, `unreachable`, or `blocked` |\n| `score` | 0-100 | Overall trust score (required if status=`evaluated`) |\n\n### Score Tags\n\n| Tag | Description |\n|-----|-------------|\n| `score` | Overall trust score (weighted combination: 40% reliability + 35% quality + 25% accessibility) |\n| `reliability` | Availability, recovery speed, consistency, and latency (0-100) |\n| `quality` | Policy documentation, security (TLS), and operator accountability (0-100) |\n| `accessibility` | Access barriers, limits, jurisdiction freedom, and surveillance risk (0-100) |\n| `confidence` | `low` (<100 obs), `medium` (100-499 obs), or `high` (500+ obs) |\n\n### Observation Tags\n\n| Tag | Format | Description |\n|-----|--------|-------------|\n| `algorithm` | string | Algorithm version (e.g., `v1`) |\n| `algorithm_url` | URL | Methodology documentation |\n| `observations` | int | Number of data points |\n| `observation_period` | string | Time period (e.g., `30d`) |\n| `first_seen` | timestamp | When first observed |\n\n### Operator Tags\n\n| Tag | Format | Description |\n|-----|--------|-------------|\n| `operator` | pubkey | Relay operator's pubkey |\n| `operator_verified` | string | `nip11_signed`, `dns`, `wellknown`, `nip11`, `vouched`, or `claimed` |\n| `operator_confidence` | 0-100 | Confidence in operator verification |\n| `operator_trust` | 0-100 | Operator's WoT trust score (from NIP-85) |\n\n### Policy Tags\n\n| Tag | Format | Description |\n|-----|--------|-------------|\n| `policy` | string | `open`, `moderated`, `curated`, or `specialized` |\n| `policy_confidence` | 0-100 | Confidence in policy classification |\n\n### Jurisdiction Tags\n\n| Tag | Format | Description |\n|-----|--------|-------------|\n| `country_code` | string | ISO 3166-1 alpha-2 country code |\n| `region` | string | State/province/region name |\n| `is_hosting` | boolean | Whether relay runs in datacenter/hosting |\n\n## Declaring Trusted Providers\n\nKind `10385` lists the user's trusted relay assertion providers:\n\n```json\n{\n  \"kind\": 10385,\n  \"tags\": [\n    [\"p\", \"<provider_pubkey_1>\", \"wss://relay.example.com\"],\n    [\"p\", \"<provider_pubkey_2>\", \"wss://relay2.example.com\"]\n  ],\n  \"content\": \"\"\n}\n```\n\nClients SHOULD check the user's kind 10385 to determine which providers to query. If none exists, clients MAY use well-known defaults.\n\n## Submitting Reports\n\nUsers submit relay reports using kind 1985 (NIP-32 Labels):\n\n```json\n{\n  \"kind\": 1985,\n  \"tags\": [\n    [\"L\", \"relay-report\"],\n    [\"l\", \"spam\", \"relay-report\"],\n    [\"r\", \"wss://relay.example.com\"]\n  ],\n  \"content\": \"Excessive spam, no moderation\"\n}\n```\n\nLabel values: `spam`, `censorship`, `unreliable`, `malicious`\n\nProviders SHOULD aggregate reports, optionally weighting by reporter's Web of Trust position.\n\n## Client Integration\n\n### NIP-46 Remote Signers\n\nWhen processing connection URIs (`nostrconnect://` or `bunker://`):\n1. Extract relay URLs from the URI\n2. Query trust assertions for each relay\n3. Display trust indicators in the UI\n\nFor `nostrconnect://` URIs (app-specified relays), this helps users evaluate unfamiliar relays before accepting a connection.\n\nFor `bunker://` URIs (signer-specified relays), this helps users verify their configured relays remain trustworthy before sharing.\n\n### Relay Discovery\n\nCombined with NIP-66:\n1. NIP-66 provides discovery (what exists)\n2. NIP-XX provides evaluation (what's good)\n\n## Final Considerations\n\nProviders SHOULD update assertions when scores change materially, not on every observation.\n\nProviders MAY limit access via paid relays.\n\nClients SHOULD cache assertions (recommended TTL: 1 hour fresh, 24 hours stale).\n\nWhen multiple providers return different scores, clients MAY average them, show a range, or let users select a preferred provider.\n\n## Relay Appeals\n\nRelay operators MAY dispute scores by publishing kind 1985 events with `L` = `relay-appeal`:\n\n```json\n{\n  \"kind\": 1985,\n  \"tags\": [\n    [\"L\", \"relay-appeal\"],\n    [\"l\", \"spam\", \"relay-appeal\"],\n    [\"r\", \"wss://relay.example.com\"],\n    [\"e\", \"<event_id_of_evidence>\"]\n  ],\n  \"content\": \"Explanation of why the score should be reconsidered...\"\n}\n```\n\nLabel values for appeals: `spam`, `censorship`, `score`, `policy`, `other`\n\nThe `e` tag MAY reference evidence events. Appeals from verified operators (high confidence) SHOULD be prioritized by providers.\n\n## References\n\n- [NIP-11 - Relay Information Document](https://github.com/nostr-protocol/nips/blob/master/11.md)\n- [NIP-32 - Labeling](https://github.com/nostr-protocol/nips/blob/master/32.md)\n- [NIP-66 - Relay Discovery and Liveness Monitoring](https://github.com/nostr-protocol/nips/blob/master/66.md)\n- [NIP-85 - Trusted Assertions](https://github.com/vitorpamplona/nips/blob/user-summaries/85.md)","sig":"141b2d879b355fe4e8912dab668d9a6233831c8c85d5ece72714f1db42bb4a7cfb3886fe0e4d3d08347512fc1d725e945ab848a0ce69b1d7058a20e01b56894f"}