Chapter 85 - Web of Trust
85
Nostr Implementation Possibility - Hex № 85

Trusted Assertions

Outsource heavy web-of-trust math to providers you pick. They publish signed scores; your client just reads them.

1 Overview

Some web-of-trust calculations need a large volume of events and much computing power. A phone client cannot crawl the whole network to rank every pubkey. This NIP moves that work to a service provider that the user declares as trusted.

The provider runs its algorithm over the network. It then publishes the results as signed Trusted Assertion events (TAs). An assertion is a small addressable event: "this pubkey has rank 89" or "this note received 12 zaps". Clients fetch these events and show the numbers.

The user stays in control through a kind 10040 list. It names the provider key and relay for each result type the user wants. Two providers can compute the same metric in different ways. The user picks the provider whose view matches their own.

Hint!

Think of a provider as a strategy guide hotline. You do not solve the whole map yourself. You call the hotline you trust, and it tells you the score. Different hotlines give different answers - that is the point.

Network many events Provider runs algorithm TA relay Client shows scores crawl kind 3038x REQ
Fig. 85-1 — Offloaded trust. The provider does the heavy computation and publishes signed assertions. The client only downloads small events.

2 Assertion Events

A Trusted Assertion is always an addressable event as defined in NIP-01. The d tag holds the subject of the assertion. The NIP recognizes four subject types. Each subject type maps to one event kind:

Subject types and kinds
SubjectEvent kindd tag value
User30382<pubkey>
Event30383<event_id>
Addressable event30384<event_address>
NIP-73 identifier30385<i-tag>

Calculation results live in pre-defined tags. Providers and clients agree on the syntax and semantics of each tag. This example ranks a pubkey with a web-of-trust score of 89:

Wire format - kind 30382 assertion
{
  "kind": 30382,
  "pubkey": <service pubkey>,
  "tags": [
    ["d", "e88a691e98d9987c964521dff60025f6…27850411"], // target user's pubkey
    ["rank", "89"]
  ],
  "content": "",
  // created_at, id, sig …
}
Warning!

A provider must use a different service key for each distinct algorithm. When an algorithm is personalized to one user's point of view or settings, the provider must use one key per user. One key, one algorithm, one viewpoint.

3 Kind 30382 — Users as Subject

Kind 30382 rates a person. The d tag holds the target pubkey. These result types are declared:

Kind 30382 result types
Result typeTag nameTag value format
Follower countfollowersint
User rankrankint, normalized 0-100
First post timefirst_created_atunix timestamp
Post countpost_cntint
Reply countreply_cntint
Reactions countreactions_cntint
Zap amount receivedzap_amt_recdint, sats
Zap amount sentzap_amt_sentint, sats
Zap number receivedzap_cnt_recdint
Zap number sentzap_cnt_sentint
Avg zap amount/day receivedzap_avg_amt_day_recdint, sats
Avg zap amount/day sentzap_avg_amt_day_sentint, sats
Reports receivedreports_cnt_recdint
Reports sentreports_cnt_sentint
Common topicststring
Generally active startactive_hours_startint, 0-24, UTC
Generally active endactive_hours_endint, 0-24, UTC

Each provider can compute these values its own way. One provider may exclude the user's muted pubkeys from the follower count. Another provider may keep them. The user picks the provider whose method matches their view. Zap metrics come from NIP-57 receipts. Report metrics come from NIP-56 events.

4 Kind 30383 — Events as Subject

Kind 30383 rates one regular event. The d tag holds the event id. Providers can attach these tags:

Kind 30383 result types
Result typeTag nameTag value format
Event rankrankint, normalized 0-100
Event comment countcomment_cntint
Event quote countquote_cntint
Event repost countrepost_cntint
Event reaction countreaction_cntint
Event zap countzap_cntint
Event zap amountzap_amountint, sats

5 Kind 30384 — Addressables as Subject

Kind 30384 rates all versions of one addressable event together. The d tag holds the event address (kind:pubkey:d-value). The tag set mirrors kind 30383:

Kind 30384 result types
Result typeTag nameTag value format
Address rankrankint, normalized 0-100
Address comment countcomment_cntint
Address quote countquote_cntint
Address repost countrepost_cntint
Address reaction countreaction_cntint
Address zap countzap_cntint
Address zap amountzap_amountint, sats

6 Kind 30385 — External Identifiers as Subject

Kind 30385 rates things outside Nostr: books, locations, movies, websites, and hashtags. The d tag holds a NIP-73 identifier (an i tag value). Add the matching NIP-73 k tags to the event as well.

Kind 30385 result types
Result typeTag nameTag value format
Rankrankint, normalized 0-100
Comment countcomment_cntint
Reaction countreaction_cntint

7 Declaring Trusted Providers — Kind 10040

A kind 10040 event lists the user's preferred source for each result. Each tag names a kind:tag pair, then the publisher's pubkey, then the relay where the assertion events live. Providers may use multiple keys and relays, including a key per user for personalized algorithms.

Users can share this list publicly as plain tags. Or they can keep it private: JSON-stringify the tag list, encrypt it with NIP-44, and store it in the content field.

Wire format - kind 10040 provider list
{
  "kind": 10040,
  "tags": [
    [<kind:tag>, <service key>, <relay hint>],
    // examples
    ["30382:rank", "4fd5e210530e4f6b…fe5f12fe", "wss://nip85.nostr.band"],
    ["30382:rank", "3d842afecd5e293f…2d44a42d", "wss://nostr.wine"],
    ["30382:zap_amt_sent", "4fd5e210530e4f6b…fe5f12fe", "wss://nip85.nostr.band"]
  ],
  "content": nip44Encrypt(JSON.stringify([
    [<kind:tag>, <service key>, <relay hint>],
    // examples
    ["30383:rank", "4fd5e210530e4f6b…fe5f12fe", "wss://nip85.nostr.band"],
    ["30384:rank", "4fd5e210530e4f6b…fe5f12fe", "wss://nip85.nostr.band"]
  ])),
  // other fields …
}

When a provider offers several algorithms, or several points of view of one algorithm, the key in each tag should point to the key created for that specific algorithm or point of view.

Tech Note

The source example is loose in two ways. First, its nip44Encrypt( call is never closed before the trailing comment. Second, it shows public tags and an encrypted content list in the same event, while the prose frames public and private as a user choice. The spec does not say how a client merges the two lists if both are present.

8 Operational Rules

  • Providers should update Trusted Assertions as fast as new information arrives. But they should re-publish an event only when its contents actually change. This avoids re-downloading the same information.
  • Providers may limit access to results by publishing to paid relays.
  • In a TA, a p, e, or a tag with the same value as the d tag may be added. It carries a relay hint to the home relay of that user or event.

9 Provider Discoverability

A provider should sign a kind 0 metadata event (NIP-01) for each service key. It explains who controls the key and what the current version of the algorithm is about:

Wire format - kind 0 for a service key
{
  "kind": 0,
  "pubkey": <service pubkey>,
  "tags": [],
  "content": "{
    \"name\": \"Vitor's Brainstormer\",
    \"about\": \"A Web of Trust algorithm from Vitor's point of view that
      considers Follows and Mutes, but no reports, and gives extra
      score points for anyone around Boston\",
    \"picture\": \"https://brainstorm.com/logo.png\",
    \"website\": \"https://brainstorm.com\"
  }",
  // other fields …
}
Tech Note

The kind 0 example in the source uses = between keys and values inside content (for example \"name\" = \"…\"). That is not valid JSON. The block above shows the intended shape with :. Treat the source example as illustrative only.

A client that wants to offer a list of providers to its users should:

  1. Download the kind 10040 events of the user's follow list.
  2. Connect to each listed relay. Download the kind 0 of each service key.
  3. Parse the kind 0 and collect the website property.
  4. Load the OpenGraph tags of that website. Display them as clickable items.
Client Relays ["REQ", "s1", {"kinds":[10040],"authors":[<user>]}] ["EVENT", "s1", {10040: provider key + relay}] ["REQ", "s2", {"kinds":[30382],"authors":[<service key>],"#d":[<pubkey>]}] sent to the relay hinted in the 10040 tag ["EVENT", "s2", {30382: ["rank","89"]}] ["EOSE", "s2"] The client renders "rank 89" next to the profile.
Fig. 85-2 — Assertion lookup. The 10040 list tells the client where to ask; the provider relay answers with the signed assertion.

10 Worked Example

Alice wants to see trust ranks in her client. She declares a provider, and her client fetches an assertion about Bob. Orange lines go to the relay. Blue lines come from the relay.

Session transcript - declaring, then reading an assertion
-- Alice publishes her provider list --
→ ["EVENT", {"kind":10040,"pubkey":"a11ce9f2…","created_at":1749821000,
     "tags":[["30382:rank","4fd5e210…","wss://nip85.nostr.band"]],
     "content":"","id":"c3f1a0d2…","sig":"90ab41ce…"}]
← ["OK", "c3f1a0d2…", true, ""]

-- Her client asks the hinted relay for Bob's assertion --
→ ["REQ", "wot", {"kinds":[30382], "authors":["4fd5e210…"],
     "#d":["b0b7c4e1a95d20fa88431fe1dd2ae9b4…13cf02aa"]}]
← ["EVENT", "wot", {"kind":30382,"pubkey":"4fd5e210…","created_at":1749820500,
     "tags":[["d","b0b7c4e1a95d20fa88431fe1dd2ae9b4…13cf02aa"],
             ["rank","89"],["followers","1204"],["zap_cnt_recd","312"],
             ["p","b0b7c4e1a95d20fa88431fe1dd2ae9b4…13cf02aa","wss://bob.example"]],
     "content":"","id":"7e2d90bc…","sig":"d4e88a01…"}]
← ["EOSE", "wot"]
-- Client shows: Bob - rank 89 - 1204 followers (per this provider) --

11 Version History

NIP-85 is young. Vitor Pamplona proposed it after a long-running pull request discussion. Notable changes, newest first:

  • 20262026-06Repo-wide cleanup by fiatjaf changed the code fence language of the examples.
  • 20262026-05Clarifications pass: tightened wording on subjects, keys, and tag semantics.
  • 20262026-02Added Appendix 1: service provider discoverability through kind 0 metadata on each service key.
  • 20262026-01Typo fixes shortly after merge.
  • Origin2026-01-22Vitor Pamplona merged the initial Trusted Assertions spec (PR #1534): kinds 30382-30385, kind 10040, and the result-type tables.

Original Proposal - Credits

AuthorVitor Pamplona
First commit2026-01-22 — “Trusted Assertions (#1534)” - PR #1534
Statusdraftoptional
Source85.md on GitHub - full change history

12 See Also

  • NIP-01 — addressable events, the d tag, and kind 0 metadata that this NIP builds on.
  • NIP-73 — external content identifiers; the subjects of kind 30385 assertions.
  • NIP-44 — the encryption used to keep a kind 10040 provider list private.
  • NIP-57 — zaps; the source of all zap amount and zap count metrics.
  • NIP-56 — reporting; the source of the report count metrics.
  • NIP-25 — reactions; the source of the reaction count metrics.