{"id":"623abfec569922adaf62ce7251f08f49589ca1c6ad902aa407184e14dbf6b7b4","pubkey":"f5c22b18c3b40e3d207ebf445524b307f01b28499c25117d4694cb9c344c21fc","created_at":1771148162,"kind":30817,"tags":[["d","clip"],["title","CLIP: Common Lightning-node Information Payload"],["k","38171"],["client","nostrhub.io"]],"content":"CLIP\n====\n\nCommon Lightning-node Information Payload\n-----------------------------------------\n\n`draft` `optional`\n\n## Abstract\n\nCLIP enables Lightning node operators to cryptographically link their node identity to a Nostr pubkey and publish verifiable node metadata (contact information, channel policies, custom records) over Nostr.\n\nCLIP uses Nostr addressable events of kind `38171`, differentiated by a `k` tag into distinct message types. A Lightning node signature provides the trust anchor that binds a Lightning node identity to a Nostr pubkey.\n\n## Event Format\n\nAll CLIP events use a single Nostr event kind:\n\n```jsonc\n{\n  \"kind\": 38171,\n  \"pubkey\": \"<nostr-pubkey-hex>\",\n  \"created_at\": <timestamp>,\n  \"tags\": [\n    [\"d\", \"<identifier>\"],\n    [\"k\", \"<clip-kind>\"],\n    // additional tags depending on kind\n  ],\n  \"content\": \"<json-payload-or-empty>\",\n  \"sig\": \"<nostr-signature>\"\n}\n```\n\nAs addressable events, relays only store the most recent version for each unique combination of `d` tag and author pubkey, automatically replacing older versions.\n\n### Tag Definitions\n\n| Tag   | Required | Description |\n|-------|----------|-------------|\n| `d`   | yes      | Unique identifier. Format depends on the CLIP kind (see Message Types). |\n| `k`   | yes      | CLIP message kind as a string (`\"0\"`, `\"1\"`, ...). |\n| `sig` | kind 0   | Lightning node signature. zbase32-encoded ECDSA signature over the event hash computed _without_ the `sig` tag (see Signature Verification). Present only on Node Announcements. |\n\n### Validation Rules\n\nIn addition to standard Nostr event validation (NIP-01), clients MUST enforce:\n\n- `content` MUST NOT exceed 1,048,576 bytes (1 MB).\n- For Kind 1 events, the `k` tag value MUST match the kind encoded in the `d` tag.\n\nClients MAY reject events from Lightning nodes with no on-chain channel capacity as a spam protection measure.\n\n## Message Types\n\n### Kind 0 -- Node Announcement\n\nA Node Announcement is a trust anchor that links a Lightning node's public key to a Nostr pubkey. It MUST be signed by both the Lightning node's identity key (via the `sig` tag) and a Nostr key (standard Nostr event signature).\n\n**`d` tag:** `<lightning_pubkey>`\n\nThe `d` tag contains the compressed public key of the Lightning node (66-character hex string).\n\n**`content`:** empty (`\"\"` or `\"{}\"`)\n\n**Additional tags:**\n\n| Tag   | Description |\n|-------|-------------|\n| `sig` | zbase32-encoded Lightning signature over the event hash (see Signature Verification). |\n\n**Example:**\n\n```json\n{\n  \"kind\": 38171,\n  \"pubkey\": \"a1b2c3d4e5f6...\",\n  \"created_at\": 1700000000,\n  \"tags\": [\n    [\"d\", \"03abc123def456...\"],\n    [\"k\", \"0\"],\n    [\"sig\", \"ryz1bnx5...\"]\n  ],\n  \"content\": \"{}\",\n  \"sig\": \"nostr-signature...\"\n}\n```\n\n### Kind 1 -- Node Info\n\nA Node Info event contains metadata about a Lightning node. It only requires a Nostr signature and MUST be signed by the Nostr key that was bound in the most recent Node Announcement for that Lightning node.\n\n**`d` tag:** `<kind>:<lightning_pubkey>:<network>`\n\nExample: `1:03abc123def456...:mainnet`\n\nValid networks: `mainnet`, `testnet`, `testnet4`, `signet`, `simnet`, `regtest`.\n\n**`content`:** JSON object with the following schema:\n\n| Field                | Type              | Description |\n|----------------------|-------------------|-------------|\n| `about`              | string            | Human-readable description of the node. |\n| `max_channel_size_sat` | integer         | Maximum channel size the operator is willing to accept (satoshis). |\n| `min_channel_size_sat` | integer         | Minimum channel size the operator requires (satoshis). |\n| `contact_info`       | array of objects  | Contact methods (see below). At most one entry MAY have `primary: true`. |\n| `custom_records`     | object            | Arbitrary string key-value pairs for additional information. |\n\nAll fields are optional.\n\nIf both `max_channel_size_sat` and `min_channel_size_sat` are present, `max_channel_size_sat` MUST be greater than or equal to `min_channel_size_sat`.\n\n**Contact Info object:**\n\n| Field     | Type    | Required | Description |\n|-----------|---------|----------|-------------|\n| `type`    | string  | yes      | Contact type (e.g., `\"nostr\"`, `\"email\"`, `\"telegram\"`). |\n| `value`   | string  | yes      | Contact address or handle. |\n| `note`    | string  | no       | Additional context about this contact method. |\n| `primary` | boolean | no       | Whether this is the preferred contact method. At most one contact MAY be primary. |\n\n**Example:**\n\n```json\n{\n  \"kind\": 38171,\n  \"pubkey\": \"a1b2c3d4e5f6...\",\n  \"created_at\": 1700000100,\n  \"tags\": [\n    [\"d\", \"1:03abc123def456...:mainnet\"],\n    [\"k\", \"1\"]\n  ],\n  \"content\": \"{\\\"about\\\":\\\"High-uptime routing node.\\\",\\\"max_channel_size_sat\\\":16777215,\\\"min_channel_size_sat\\\":100000,\\\"contact_info\\\":[{\\\"type\\\":\\\"nostr\\\",\\\"value\\\":\\\"npub1...\\\",\\\"primary\\\":true},{\\\"type\\\":\\\"email\\\",\\\"value\\\":\\\"node@example.com\\\"}],\\\"custom_records\\\":{\\\"acceptance_policy\\\":\\\"Accepting channels from reliable nodes.\\\"}}\",\n  \"sig\": \"nostr-signature...\"\n}\n```\n\n## Signature Verification\n\nNode Announcements (Kind 0) require a Lightning node signature in the `sig` tag. This signature binds the Lightning node identity to the Nostr event.\n\n### Signed Message\n\nThe signed message is the **event hash** of the event _without_ the `sig` tag. This hash is the Nostr event ID, i.e., the hex-encoded SHA-256 of the canonical JSON serialization `[0, pubkey, created_at, kind, tags_without_sig, content]`.\n\nSpecifically, the `sig` tag is excluded from the tags array before computing the event ID. This means the signature covers the Nostr pubkey, the Lightning pubkey (in the `d` tag), the timestamp, and all other event content.\n\n### Signature Format\n\nThe signature follows the LND `SignMessage` RPC format:\n\n1. The message bytes are prefixed with `\"Lightning Signed Message:\"` (no null terminator).\n2. The prefixed message is double-SHA-256 hashed: `SHA256(SHA256(\"Lightning Signed Message:\" || message))`.\n3. The result is signed with the node's identity key using ECDSA (secp256k1), producing a compact recoverable signature.\n4. The signature is encoded as zbase32.\n\n### Verification Procedure\n\nTo verify a Node Announcement:\n\n1. Extract the `sig` tag value and decode from zbase32.\n2. Compute the event hash (event ID) over the event _without_ the `sig` tag.\n3. Prefix the hash with `\"Lightning Signed Message:\"` and compute the double-SHA-256.\n4. Recover the public key from the compact ECDSA signature.\n5. Compare the recovered public key (compressed, hex-encoded) against the `d` tag value.\n6. If they match, the signature is valid.\n\n## Trust Model\n\nThe trust model ensures that only the legitimate node operator can publish information for a given Lightning node.\n\n### Establishing Trust\n\nA Node Announcement (Kind 0) establishes which Nostr pubkey is authorized to publish events for a Lightning node. The Lightning signature proves the announcement was created by (or authorized by) the node operator.\n\n### Key Rotation (nsec Compromise)\n\nIf a node operator's Nostr key is compromised, they can publish a new Node Announcement with a different Nostr pubkey. Clients MUST handle this as follows:\n\n1. Among all Node Announcements for a given Lightning pubkey, only the one with the most recent `created_at` is considered valid.\n2. If the new announcement uses a different Nostr pubkey than the previous one, **all prior events** for that node MUST be discarded.\n3. Only events signed by the Nostr pubkey from the most recent announcement are accepted.\n\nNote: Since Node Announcements are addressable events with different Nostr author pubkeys, relays will store both the old and new announcements. Clients are responsible for selecting the most recent one.\n\n### Event Acceptance\n\nBefore accepting a Kind 1 event, clients MUST:\n\n1. Fetch all Node Announcements for the corresponding Lightning pubkey to establish the trust anchor.\n2. Determine the most recent Node Announcement (by `created_at`).\n3. Reject the event if its Nostr pubkey does not match the most recent announcement's Nostr pubkey.\n\n## References\n\n- [Nostr Protocol (NIP-01)](https://github.com/nostr-protocol/nips/blob/master/01.md) -- Basic protocol\n- [Addressable Events (NIP-33)](https://github.com/nostr-protocol/nips/blob/master/33.md) -- Parameterized replaceable events\n- [clip](https://github.com/feelancer21/clip) -- Reference implementation","sig":"48a49dc245f5087fa4e35b9cfa88fc45b03fbdecae5a405d7cd9a84ad43a4413761d37c4b042e7857c9f3ef1809c901ad9e4de8342646d653cb52303e1611511"}