Compare commits

...

8 Commits

Author SHA1 Message Date
jab-r 325055eb96
Merge 7c8a9170c3 into 74681c3c14 2025-10-08 20:53:42 -04:00
Vitor Pamplona 74681c3c14
NIP-45 is not a subscription. Changing to query id to reduce confusion. (#2083) 2025-10-08 17:43:37 -05:00
jab-r 7c8a9170c3
Merge branch 'master' into master 2025-08-27 13:30:35 -04:00
jab-r 3b19239095
Update README with new NIP-EE and NIP-XXX entries 2025-08-27 13:28:58 -04:00
jab-r 494dd3e146
Revise NIP for encrypted binary attachments in DMs
This update revises the NIP to focus on encrypted binary attachments for private messaging, clarifying the scope, specifications, and security considerations. Changes include rewording sections, updating examples, and emphasizing the use of encryption in attachments.
2025-08-26 22:13:55 -04:00
jab-r befaa2882d
Revise author info and improve encryption details 2025-08-26 11:29:06 -04:00
jab-r a0f0162947
draft entry for Binary Attachments 2025-08-23 13:50:37 -04:00
jab-r e315561630
Add NIP-XXX: Binary Attachments for Notes and DMs 2025-08-23 13:47:17 -04:00
3 changed files with 203 additions and 11 deletions

22
45.md
View File

@ -14,17 +14,17 @@ Some queries a client may want to execute against connected relays are prohibiti
## Filters and return values
This NIP defines the verb `COUNT`, which accepts a subscription id and filters as specified in [NIP 01](01.md) for the verb `REQ`. Multiple filters are OR'd together and aggregated into a single count result.
This NIP defines the verb `COUNT`, which accepts a query id and filters as specified in [NIP 01](01.md) for the verb `REQ`. Multiple filters are OR'd together and aggregated into a single count result.
```
["COUNT", <subscription_id>, <filters JSON>...]
["COUNT", <query_id>, <filters JSON>...]
```
Counts are returned using a `COUNT` response in the form `{"count": <integer>}`. Relays may use probabilistic counts to reduce compute requirements.
In case a relay uses probabilistic counts, it MAY indicate it in the response with `approximate` key i.e. `{"count": <integer>, "approximate": <true|false>}`.
```
["COUNT", <subscription_id>, {"count": <integer>}]
["COUNT", <query_id>, {"count": <integer>}]
```
Whenever the relay decides to refuse to fulfill the `COUNT` request, it MUST return a `CLOSED` message.
@ -34,27 +34,27 @@ Whenever the relay decides to refuse to fulfill the `COUNT` request, it MUST ret
### Followers count
```
["COUNT", <subscription_id>, {"kinds": [3], "#p": [<pubkey>]}]
["COUNT", <subscription_id>, {"count": 238}]
["COUNT", <query_id>, {"kinds": [3], "#p": [<pubkey>]}]
["COUNT", <query_id>, {"count": 238}]
```
### Count posts and reactions
```
["COUNT", <subscription_id>, {"kinds": [1, 7], "authors": [<pubkey>]}]
["COUNT", <subscription_id>, {"count": 5}]
["COUNT", <query_id>, {"kinds": [1, 7], "authors": [<pubkey>]}]
["COUNT", <query_id>, {"count": 5}]
```
### Count posts approximately
```
["COUNT", <subscription_id>, {"kinds": [1]}]
["COUNT", <subscription_id>, {"count": 93412452, "approximate": true}]
["COUNT", <query_id>, {"kinds": [1]}]
["COUNT", <query_id>, {"count": 93412452, "approximate": true}]
```
### Relay refuses to count
```
["COUNT", <subscription_id>, {"kinds": [4], "authors": [<pubkey>], "#p": [<pubkey>]}]
["CLOSED", <subscription_id>, "auth-required: cannot count other people's DMs"]
["COUNT", <query_id>, {"kinds": [1059], "#p": [<pubkey>]}]
["CLOSED", <query_id>, "auth-required: cannot count other people's DMs"]
```

View File

@ -107,6 +107,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
- [NIP-C0: Code Snippets](C0.md)
- [NIP-C7: Chats](C7.md)
- [NIP-EE: E2EE Messaging using MLS Protocol](EE.md)
- [NIP-XXX: Encrypted Binary Attachments | DRAFT](nip-xxx-binary-attachments.md)
## Event Kinds
| kind | description | NIP |

View File

@ -0,0 +1,191 @@
---
nip: XXX
title: Encrypted Binary Attachments for DMs and MLS
author: Jonathan Borden (jonathan@loxation.com)
status: Draft
type: Standards Track
created: 2025-08-23
license: CC0-1.0
---
## Abstract
This NIP profile standardizes encrypted binary attachments (images, audio, video, documents) for private Nostr messaging only: NIP17 direct messages and MLS groups. It defines:
- A normalized JSON structure for NIP17 DMs (keys live only inside the DM ciphertext)
- An MLS profile that derives perattachment AEAD key/nonce via the MLS exporter
- A perattachment AEAD scheme (AES256GCM) with normative sizes
- Integrity requirements (SHA256 over ciphertext)
- HTTP storage guidance (presigned upload/finalize), optionally compatible with NIP96 and NIP98
Public, unencrypted tags (attach/eattach) are explicitly out of scope for this profile.
## Motivation
Clients and servers need a consistent, interoperable, privacypreserving mechanism for sharing files in private contexts. This document scopes the solution to encryptedonly delivery via NIP17 (1:1) and MLS (1:group), which matches our deployment and avoids ambiguity and leakage associated with public note tags.
## Rationale
- Keep symmetric keys in encrypted channels only (DM content or MLS exporter). Never in public tags or relayvisible metadata.
- Use perattachment AEAD to avoid key reuse and enable granular sharing and revocation.
- Compute integrity over ciphertext so clients can verify prior to decryption and rendering.
- Keep events lightweight; store bytes offrelay at canonical HTTPS URLs.
## Definitions
- **Attachment**: A binary resource referenced by a message.
- **Ciphertext attachment**: Uploaded bytes are encrypted; clients decrypt locally to render.
- **Perattachment key**: A random 32byte AES256 key generated uniquely per attachment (DMs). For MLS, the key is derived via the exporter.
## Specification
### 1. Cipher and integrity
- AEAD: AES256GCM
- key: 32 bytes (base64) [DMs only; MLS derives]
- iv/nonce: 12 bytes (base64)
- tag: 16 bytes (base64)
- Integrity: sha256 MUST be computed over ciphertext and verified before decrypt/render.
### 2. NIP17 direct messages (DMs)
Attachment parameters MUST live inside the DMs encrypted content (not tags). The DM plaintext embeds a normalized JSON array of attachment objects:
```json
{
"type": "message",
"text": "optional user text",
"attachments": [
{
"url": "https://storage.example/enc/blob",
"ct": "image/jpeg",
"size": 23011,
"sha256": "<hex_of_ciphertext>",
"fn": "photo.jpg",
"enc": {
"mode": "dm",
"algo": "A256GCM",
"k": "<b64-32-bytes>",
"iv": "<b64-12-bytes>",
"t": "<b64-16-bytes>"
},
"alt": "a cat",
"blurhash": "..."
}
]
}
```
Receiver processing:
1) Decrypt the DM per NIP17.
2) Fetch the ciphertext bytes from `url`.
3) Verify `sha256` over ciphertext.
4) Decrypt with `enc.k/iv/t`.
5) Render using `ct`, `fn`, `alt`, and optional hints (e.g., `blurhash`).
Notes:
- The `size` field SHOULD reflect ciphertext length.
- Clients SHOULD cache both ciphertext and decrypted plaintext for efficient rerendering.
### 3. MLS group attachments
For MLS application messages, the attachment AEAD key and nonce are derived via the MLS exporter; no symmetric key material is placed in relayvisible metadata.
Key/nonce derivation (normative):
- key = MLS.exporter(label="attachment", context=concat(epoch, "|", ctx), length=32)
- nonce = MLS.exporter(label="attachment-nonce", context=concat(epoch, "|", ctx), length=12)
Where `ctx` is a stable, mutually known identifier for this attachment (e.g., server `blobId` or a messagescoped `attachmentId`). Publishers MUST include enough metadata for receivers to compute the same `ctx`.
Attachment metadata embedded in or adjacent to the MLS application message SHOULD include:
```json
{
"url": "https://storage.example/enc/blob",
"ct": "image/jpeg",
"size": 23011,
"sha256": "<hex_of_ciphertext>",
"fn": "photo.jpg",
"enc": {
"mode": "mls",
"algo": "A256GCM",
"t": "<b64-16-bytes>",
"mls": { "group_id": "<groupId>", "epoch": 42, "ctx": "<blobId|attachmentId>" }
}
}
```
Receiver processing:
1) Use MLS state for `group_id`/`epoch` to derive key and nonce with the exporter and `ctx`.
2) Fetch ciphertext, verify `sha256`, then decrypt with derived key/nonce and verify auth tag `t`.
### 4. Out of scope
- Public note tags for unencrypted or encrypted media (attach/eattach).
- NIP92 “imeta” and NIP94 filemetadata records for public media.
This profile targets encrypted attachments delivered via NIP17 and MLS only.
### 5. Storage and transport
- Storage: Offrelay HTTP object storage with presigned upload + finalize flows that return canonical download URLs and servercomputed metadata (size/checksum). These flows are compatible with NIP96 where applicable.
- Auth: Publishers and storage providers MAY require NIP98 (HTTP Auth) for upload/finalize/download.
- Alternate device transports (e.g., BLE/Noise) MAY carry the same JSON payloads; this does not change the onwire format for Nostr DMs or MLS.
### 6. Client behavior
- Verify `sha256` over ciphertext before decrypt/render.
- Verify GCM auth tag during decryption.
- Show filename/thumbnail; respect accessibility fields like `alt`.
- Cache intelligently; apply quotas and safecontent policies when fetching.
### 7. Security considerations
- Do not place keys, IVs, or tags in public tags or content.
- Do not include encryption material in NIP92 `imeta` or any relayvisible metadata.
- Treat URLbased key delivery or external key references as nonconfidential; this profile forbids such patterns.
- Ensure unique IVs per key; perattachment keys simplify this, but libraries MUST still generate fresh IVs.
## Examples
### NIP17 DM with encrypted attachment
```json
{
"type": "message",
"attachments": [
{
"url": "https://cdn.example/enc/xyz",
"ct": "image/jpeg",
"size": 23011,
"sha256": "55aa...",
"fn": "photo.jpg",
"enc": { "mode": "dm", "algo": "A256GCM", "k": "...", "iv": "...", "t": "..." }
}
]
}
```
### MLS attachment metadata (ciphertext at URL; key/nonce via exporter)
```json
{
"url": "https://cdn.example/enc/xyz",
"ct": "video/mp4",
"size": 8329001,
"sha256": "2f3a...",
"fn": "talk.mp4",
"enc": {
"mode": "mls",
"algo": "A256GCM",
"t": "....",
"mls": { "group_id": "deadbeef", "epoch": 42, "ctx": "blob:e3b0c442..." }
}
}
```
## Implementation Status
- Reference client: **loxationsw**
- Supports perattachment AES256GCM, presigned upload/finalize, NIP17 DM JSON payloads, and UI rendering.
- MLS exporterbased attachments are supported in the MLS messaging flows used by Loxation.