NIP Support
Nostr is defined by its NIPs : Nostr
Implementation Possibilities. Here’s where zig-nostr stands. Every “done” NIP
is covered by tests, and the cryptographic ones are verified against their
official specification vectors.
| NIP | Title | Status |
|---|---|---|
| 01 | Basic protocol: events, signatures, subscriptions, kind:0 profiles and kind:1 notes | ✅ done |
| 04 | Legacy encrypted direct messages, kind:4 (AES-256-CBC with an ?iv= payload). Interoperability only: it has no authentication, so a successful decrypt proves nothing about who wrote the message | ✅ done |
| 05 | DNS identifiers, /.well-known/nostr.json: the identifier is parsed and normalized and the response is read for the pubkey and relays. A codec only, the library does no HTTP; deed does the lookup | ✅ done |
| 06 | Key derivation from a BIP-39 mnemonic, path m/44'/1237'/<account>'/0/0 | ✅ done |
| 11 | Relay information documents: the document is parsed, and a field of the wrong type is skipped without losing the rest. A codec only, the library does no HTTP; deed fetches the document | ✅ done |
| 13 | Proof of work: counting the leading zero bits of an id, reading the target committed in a nonce tag, and mining a nonce to a target | ✅ done |
| 09 | Event deletion, kind:5 (ingestion) | ✅ done |
| 19 | bech32-encoded entities: npub, nsec, note, nprofile, nevent, naddr. A code is read in all lowercase or all uppercase, and one that mixes the two is refused | ✅ done |
| 17 | Private direct messages: building the kind:14 message and its wraps with NIP-59, and reading one back. Relay lists for delivery (kind:10050) and file messages (kind:15) are not handled | ✅ done |
| 21 | nostr: URI scheme, with the scheme matched in any case, so the NOSTR: a QR code carries decodes | ✅ done |
| 42 | Client-to-relay authentication: answering a relay’s AUTH challenge with a kind:22242 event | ✅ done |
| 44 | Encrypted payloads (v2) | ✅ done |
| 45 | Event counts: the COUNT request and the relay reply, encoded and parsed. The local store counts too, with deed | ✅ done |
| 46 | Nostr Connect, remote signing over kind:24133: the signer side, and a client that connects to a signer by bunker:// or nostrconnect://. The client is marked experimental and its shape may still change | ✅ done |
| 49 | Private key encryption (ncryptsec) | ✅ done |
| 50 | Search: the search field of a filter, sent to relays as "search". Relays decide what matches, so the library’s own matching ignores it, and the local store applies it as a case-insensitive substring of the content | ✅ done |
| 29 | group reads a group’s info, members, admins and chat, joins and leaves, sends messages, and makes the admin moderation calls. A group is addressed as relay'group-id | |
| 34 | git reads repository announcements, state, patches, issues and pull requests, announces a repository, and sends a series of patches. Patches of 60 kB or more are refused | |
| 4E | dekey announces a decoupled encryption key and sends it to devices that ask, only when told to with --authorize-all | |
| 5A | nsite deploys, downloads and lists static sites. A file is written only when its bytes hash to the name in the manifest | |
| 59 | Gift wrap: the rumor, the seal (kind:13) and the wrap (kind:1059), with the seal and wrap timestamps moved back at random and the sender proven by the seal alone | ✅ done |
| 65 | Relay list metadata, kind:10002, what people call the outbox model | ✅ done |
| 77 | Negentropy set reconciliation, protocol version 1, with the NEG-OPEN, NEG-MSG, NEG-CLOSE and NEG-ERR messages. The tests replay transcripts recorded from the reference implementation | ✅ done |
| 86 | Relay management API: requests encoded and responses parsed, with the NIP-98 header that authorizes them. The library does no HTTP | ✅ done |
| 98 | HTTP authentication: building and reading the kind:27235 event and the Authorization: Nostr header, and checking one on the server side. The library does no HTTP | ✅ done |
| Blossom | Media authorization (kind:24242, BUD-01, BUD-02 and BUD-11 headers) and blob descriptors. Not NIPs: Blossom documents are called BUDs. The library builds the header and parses the descriptor, and does no HTTP | ✅ done |
That is the library surface, and all of it is done. What the roadmap commits to next is further down this page.
In deed
deed uses the library for the protocol and adds the network. Where a row says deed does the lookup, that is the part the library leaves out.
| NIP | What deed does |
|---|---|
| 04 | encrypt --nip04 and decrypt --nip04, for older clients. NIP-44 is the default |
| 05 | decode name@domain looks the identifier up over https and prints the pubkey and relays the domain lists. A redirect is an error |
| 11 | relay fetches each relay’s information document and prints it |
| 13 | event --pow <bits> mines a nonce on every core, with a time limit if you set one |
| 17 | gift dm builds a kind:14 message for each recipient plus a copy for you, wrapped, and prints the wraps for publish. It sends nothing itself |
| 42 | --auth on req, fetch and publish answers a relay’s challenge. Without it deed signs nothing it was not asked to sign |
| 45 | count asks relays how many events match, or counts a local store. A relay that does not support it is named and left out |
| 46 | bunker runs a signer and prints a bunker:// URI. Only authorized clients are served. A remote signer is not yet accepted wherever deed takes a key |
| 59 | gift wrap and gift unwrap, with the failed check named when an unwrap fails |
| 65 | relays prints where a person reads and writes. req --outbox, fetch, post and profile follow it, and outbox manages the lists cached in a store |
| 77 | sync between two relays, or a relay and a store. A relay without NIP-77 is asked with a plain REQ |
| 86 | admin makes a management call, signed with your key |
| 98 | curl signs the request it is about to make. A body read from a file or sent with -F is not hashed into the event |
| Blossom | blossom lists, uploads, downloads, deletes, checks and mirrors blobs. An upload counts only when the server’s hash and size match the file |
In the apps
The library gives an app the protocol. These are implemented above it, in Plaza, and are listed separately because they are client behaviour rather than library surface.
| NIP | Title | Where |
|---|---|---|
| 02 | Contact lists, kind:3 | reading and writing your follows |
| 05 | DNS identifiers, /.well-known/nostr.json | the name@domain handle on a profile, checked against the domain, and the search field resolves one to the person it names |
| 19 | bech32-encoded entities, nostr: links | opens npub, nprofile, note, nevent and naddr. An address Plaza copies carries up to two relay hints, and the account menu copies an nprofile that names the relays you write to |
| 10 | Reply threading, marked e tags | threads read by their markers, and replies you post with a root marker and a relay hint when Plaza knows one |
| 18 | Reposts, kind:6 and kind:16 | reposts are read and shown in the feed as the note itself, counted on a note, and a row in notifications. A repost Plaza publishes carries the note’s relay hint, and a quote is published as a q tag |
| 22 | Comments, kind:1111, the other way to write a reply | read in threads, on a profile, and as a notification |
| 24 | The t tag: a hashtag is a lowercase t, and NIP-01 single-letter indexing is what makes #t queryable | pressing one opens the notes carrying it, read from this machine first and then asked of relays. Written onto notes you post, so yours are findable too |
| 25 | Reactions, kind:7 | likes, in the feed and notifications |
| 27 | nostr: mentions in content | a reference to a person is shown as the name, and the first reference to a note or an article becomes a quote card. A quote you write is composed as one |
| 23 | Long-form content, kind:30023 | an article opens in a reader, from a press or from an naddr. A draft (kind:30024) is not opened, and Plaza does not write articles |
| 36 | Sensitive content, the content-warning tag | a note that carries the tag is covered until you press Show, with nothing in it fetched, and the composer adds the tag when you ask |
| 42 | Relay authentication | Plaza answers a relay’s AUTH challenge only after the relay has refused something for want of one, and only once you have allowed it for that relay and account |
| 50 | Search | three search relays are asked for people by name, and each result says which relay returned it. Profiles only, not notes |
| Blossom | Media servers: BUD-02 upload, BUD-03 server list (kind:10063), BUD-06 preflight, BUD-11 authorization (kind:24242) | a picture goes to the first server in your list that takes it, or to one of two built in when you have none. Plaza checks a server first with BUD-06, signs the BUD-11 token, and reads and edits your list |
| 89 | Application handlers | the client tag on notes you post |
| 92 | Media attachments, imeta | dimensions and placeholder read off the tag, so an image reserves its box before it loads, and written onto a picture Plaza uploads (url, type, hash, size, dimensions, blurhash and description) |
| 51 | Lists: bookmarks (kind:10003) and mutes (kind:10000) | bookmarks public or private, and a mute list that is read before it is ever written |
| 57 | Zaps, kind:9735 receipts | receipts are read and shown. Sending is a milestone away |
| 71 | Video events, kind:21 and kind:22 | a video is recognised as one and drawn as one. Playing it in place is still to come |
| 65 | Relay lists, kind:10002 | per-author routing: the feed reads where the people you follow write, and what you post goes where your own list says |
Planned, and where it lands
These are the specs the roadmap commits to, in roadmap order, each against the milestone that delivers it. A spec named here is a promise: if one is missing, it is because I have not made that promise, not because I forgot it.
| Spec | Title | Milestone | Status |
|---|---|---|---|
| NIP-24 | Extra kind:0 fields (display_name, website, banner, bot, birthday), carried through untouched when I rewrite a profile | Your identity, and your key | 🚧 planned |
| NIP-B7 | Finding a blob again: when a media URL ends in a sha256, retry it against the author’s kind:10063 servers and check the hash | Media worth looking at | 🚧 planned |
| NIP-57 | Zaps you can send: a kind:9734 request to the recipient’s LNURL callback, and the kind:9735 receipt that follows the payment | Money, carefully | 🚧 planned |
| NIP-47 | Nostr Wallet Connect, so that invoice is paid in the app: a nostr+walletconnect:// link, over kinds 13194, 23194 and 23195 | Money, carefully | 🚧 planned |
| NIP-61 | Nutzaps: Cashu ecash sent straight to a pubkey (kind:9321), gated on a kind:10019 naming the mints you trust. No LNURL provider in the path, which is what makes a brand-new account payable | Money, carefully | 🚧 planned |
| NIP-60 | The wallet that holds what arrives: kind:17375 wallet, kind:7375 tokens, kind:7376 spending history, which NIP-61 reuses to mark a nutzap redeemed | Money, carefully | 🚧 planned |
| NIP-17 | Private direct messages in Plaza: kind:14 chat, kind:15 files, and the kind:10050 relay list they are delivered to. The library builds and reads the messages already | Private messages | 🚧 planned |
| NIP-59 | Gift wrap in Plaza, which does the wrapping NIP-17 defers: a kind:13 seal signed by me, inside a kind:1059 wrap signed by a throwaway key. The library has the wrapping already | Private messages | 🚧 planned |
| NIP-29 | Groups, which live on one relay: an h tag on every event, relay-published metadata (kind:39000), and join and leave requests (kind:9021, kind:9022) | Groups | 🚧 planned |
Blossom is not a NIP. It is a separate protocol with its own repository, hzrd149/blossom , and its documents are called BUDs rather than NIPs. It sits in the apps table above because it is where file upload actually happens, and Plaza uploads a picture through it today.
NIP-B7 is the Nostr side of the same story, and it is easy to mistake for the
upload spec. It is not one. It only says how to find a blob again, so a client
that implemented it and nothing else could not upload anything at all. The older
upload NIP, NIP-96 ,
is marked unrecommended in the NIPs repo and replaced by Blossom. I do not
implement it.
Zaps lean on something that is not a NIP either. The recipient’s LNURL pay
endpoint hands back the invoice, and it is that server, not my app, that signs
and publishes the kind:9735 receipt. A pubkey whose LNURL endpoint has not
opted into Nostr cannot be zapped at all.
That last sentence is the reason nutzaps are on the list rather than filed as a
duplicate of zaps. Lightning zaps only reach somebody who signed up with an
LNURL provider before you tried to pay them, so the people least likely to be
paid are the ones who just arrived. Ecash carries its own cost in exchange: a
mint is a custodian holding real value, both specs are draft and optional,
and client support is still thin. That belongs on screen when somebody picks a
mint, not buried in a setting.
Three milestones name no spec, and inventing one for them would be dishonest. Notifications is assembled out of NIPs already on this page: NIP-10 replies, NIP-22 comments, NIP-18 reposts, NIP-25 reactions, NIP-27 mentions and NIP-57 zap receipts. Packaging, updates and diagnostics are not protocol work. Neither is a light theme, keyboard operation, or type that scales.
Named, and not doing
Refusing is a promise too, and these are the ones I get asked about. The roadmap has the rest.
- NIP-77 in Plaza. The library and deed implement it. In the client, relay support is thin and per-relay cursors capture most of the benefit against a store that already answers a feed query in under a millisecond.
- NIP-96 , HTTP
file storage. Marked
unrecommendedin the NIPs repo and replaced by Blossom. Media goes through Blossom instead. - NIP-13 in
Plaza. The library mines and deed’s
event --powuses it, but no mainstream relay I have checked advertises amin_pow_difficultyabove zero in its NIP-11 document, so the client has no use for it yet.