From ae996730923cbfd8bf8f3f4bec52a197068f1fa5 Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Thu, 11 Sep 2025 16:12:24 +0100 Subject: [PATCH 1/4] feat: ohttp mint --- 26.md | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 26.md diff --git a/26.md b/26.md new file mode 100644 index 00000000..79e0a8b3 --- /dev/null +++ b/26.md @@ -0,0 +1,75 @@ + +# NUT-26: OHTTP Transport for Mint APIs + +`optional` + +`depends on: NUT-06` + +--- + +This NUT specifies how a Cashu mint can offer its HTTP API over Oblivious HTTP (OHTTP) to improve network‑level privacy for wallets. OHTTP lets a client send encrypted requests to an oblivious gateway (optionally via a relay). The gateway decrypts, forwards the plaintext HTTP request to the mint, and encrypts the response, preventing the mint from learning the client's network address and preventing the relay from seeing request contents. + +This NUT does not change any existing Cashu API semantics. It only defines discovery and endpoints needed to use OHTTP with a mint. + +## Terminology + +- OHTTP: Oblivious HTTP as specified by the IETF OHAI working group. +- Gateway: The component that holds the OHTTP key config, decapsulates requests, forwards them to the mint backend, and encapsulates responses. +- Relay: A forwarder that sees only encrypted OHTTP messages and forwards them to the gateway. + +## Discovery via NUT‑06 + +Mints advertise OHTTP support in the `nuts` section of the [NUT‑06][06] `GetInfoResponse`. + +```json +"nuts": { + ..., + "26": { + "enabled": true, + "gateway_url": "https://ohttp.example.com" // optional + } +} +``` + +Fields: + +- `enabled` (bool): Set to `true` when the mint supports OHTTP. +- `gateway_url` (str|null, optional): Base URL of the OHTTP gateway to use for key discovery (and, by convention, for the OHTTP gateway endpoint). If omitted or `null`, clients SHOULD assume the gateway is available on the mint's own origin. + +Wallets SHOULD treat `gateway_url` as a hint for where to fetch OHTTP keys. A mint MAY operate the gateway on the same origin as the mint API, in which case `gateway_url` can be omitted. + +## Gateway Endpoints + +A gateway MUST expose the following endpoints: + +- `GET /ohttp-keys` → returns the OHTTP key configuration + - Response content type: `application/ohttp-keys` + - Body: opaque binary OHTTP key configuration as defined by the OHTTP specification + +- `POST /.well-known/ohttp-gateway` → accepts encapsulated OHTTP requests + - Request content type: `message/ohttp-req` + - Response content type: `message/ohttp-res` + - Body: opaque binary as defined by OHTTP + +A deployment MAY route additional paths to the same handler (e.g., a catch‑all that accepts `message/ohttp-req`); clients MUST NOT rely on nonstandard paths. + +## Client Behavior + +- Key fetch: Wallets fetch the OHTTP key configuration from `gateway_url + "/ohttp-keys"`. If `gateway_url` is not provided, wallets SHOULD fetch from the mint origin at `"/ohttp-keys"`. +- Encapsulation: Wallets construct a BHTTP request that mirrors a normal Cashu API call (method, scheme, authority, path, headers, and body), encapsulate it with the fetched key config, and send it to the OHTTP gateway endpoint at `"/.well-known/ohttp-gateway"` through a relay. +- Headers: Wallets include the same application‑level headers they would send directly to the mint (e.g., auth headers if applicable). The gateway forwards headers to the mint backend. +- Paths: The BHTTP request path is the regular Cashu API path (e.g., `/v1/mint/quote/bolt11`, `/v1/melt/bolt11`, `/v1/swap`, etc.). The gateway forwards the request to the mint backend preserving method, path, headers, and body. + +Wallets MUST send OHTTP messages through a relay to the gateway. + +## Errors + +Gateways SHOULD respond with appropriate HTTP status codes for transport‑level errors. Since request/response bodies are OHTTP‑encapsulated, application‑level Cashu errors remain unchanged and are handled by the wallet after decapsulation. + +## Security Considerations + +- OHTTP provides network‑level unlinkability between client and mint. It does not hide application data from the gateway operator; the gateway must be trusted to forward requests without inspection or logging unless operated by the mint itself and configured for stateless processing. +- Mints MUST publish valid OHTTP key configurations and rotate them as needed per the OHTTP specification. +- Wallets SHOULD validate URLs derived from mint info to avoid SSRF or downgrade attacks. If both direct HTTP and OHTTP are available, wallets SHOULD prefer OHTTP when a relay/gateway is configured and keys can be fetched successfully. + +[06]: 06.md From 7ac57b6e2df6fc92dfa0f2a81596090daa3f1d15 Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Fri, 12 Sep 2025 12:00:57 +0100 Subject: [PATCH 2/4] fix: review comments --- 26.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/26.md b/26.md index 79e0a8b3..ed48301a 100644 --- a/26.md +++ b/26.md @@ -17,6 +17,8 @@ This NUT does not change any existing Cashu API semantics. It only defines disco - Gateway: The component that holds the OHTTP key config, decapsulates requests, forwards them to the mint backend, and encapsulates responses. - Relay: A forwarder that sees only encrypted OHTTP messages and forwards them to the gateway. +For optimal privacy, the relay and mint SHOULD be operated by different entities that do not collude. The privacy guarantees of OHTTP depend on the relay and mint not working together to correlate user traffic patterns. + ## Discovery via NUT‑06 Mints advertise OHTTP support in the `nuts` section of the [NUT‑06][06] `GetInfoResponse`. @@ -40,23 +42,22 @@ Wallets SHOULD treat `gateway_url` as a hint for where to fetch OHTTP keys. A mi ## Gateway Endpoints -A gateway MUST expose the following endpoints: - -- `GET /ohttp-keys` → returns the OHTTP key configuration - - Response content type: `application/ohttp-keys` - - Body: opaque binary OHTTP key configuration as defined by the OHTTP specification +A gateway MUST expose the following endpoint: +- `GET /.well-known/ohttp-gateway` → returns the OHTTP key configuration - `POST /.well-known/ohttp-gateway` → accepts encapsulated OHTTP requests - Request content type: `message/ohttp-req` - Response content type: `message/ohttp-res` - Body: opaque binary as defined by OHTTP +The GET method returns the OHTTP key configuration with content type `application/ohttp-keys` as specified in RFC 9540. + A deployment MAY route additional paths to the same handler (e.g., a catch‑all that accepts `message/ohttp-req`); clients MUST NOT rely on nonstandard paths. ## Client Behavior -- Key fetch: Wallets fetch the OHTTP key configuration from `gateway_url + "/ohttp-keys"`. If `gateway_url` is not provided, wallets SHOULD fetch from the mint origin at `"/ohttp-keys"`. -- Encapsulation: Wallets construct a BHTTP request that mirrors a normal Cashu API call (method, scheme, authority, path, headers, and body), encapsulate it with the fetched key config, and send it to the OHTTP gateway endpoint at `"/.well-known/ohttp-gateway"` through a relay. +- Key fetch: Wallets fetch the OHTTP key configuration from `gateway_url + "/.well-known/ohttp-gateway"` using a GET request. If `gateway_url` is not provided, wallets SHOULD fetch from the mint origin at `"/.well-known/ohttp-gateway"`. +- Encapsulation: Wallets construct a BHTTP request ([RFC 9292](https://www.rfc-editor.org/info/rfc9292)) that mirrors a normal Cashu API call (method, scheme, authority, path, headers, and body), encapsulate it with the fetched key config, and send it to the OHTTP gateway endpoint at `"/.well-known/ohttp-gateway"` through a relay. - Headers: Wallets include the same application‑level headers they would send directly to the mint (e.g., auth headers if applicable). The gateway forwards headers to the mint backend. - Paths: The BHTTP request path is the regular Cashu API path (e.g., `/v1/mint/quote/bolt11`, `/v1/melt/bolt11`, `/v1/swap`, etc.). The gateway forwards the request to the mint backend preserving method, path, headers, and body. @@ -64,11 +65,18 @@ Wallets MUST send OHTTP messages through a relay to the gateway. ## Errors -Gateways SHOULD respond with appropriate HTTP status codes for transport‑level errors. Since request/response bodies are OHTTP‑encapsulated, application‑level Cashu errors remain unchanged and are handled by the wallet after decapsulation. +### Transport-Level Errors + +Relays SHOULD forward HTTP responses from the gateway transparently, including error status codes. Gateways SHOULD respond with appropriate HTTP status codes for transport‑level errors (e.g., malformed OHTTP requests, key configuration issues). + +### Application-Level Errors + +Since request/response bodies are OHTTP‑encapsulated, application‑level Cashu errors from the mint backend remain unchanged and are handled by the wallet after decapsulation. The relay and gateway transparently forward these errors without modification. ## Security Considerations - OHTTP provides network‑level unlinkability between client and mint. It does not hide application data from the gateway operator; the gateway must be trusted to forward requests without inspection or logging unless operated by the mint itself and configured for stateless processing. +- **Non-Collusion Requirement**: OHTTP's privacy guarantees rely on the relay and mint not colluding (working together to deanonymize users). For this reason, the relay and mint SHOULD be operated by different entities that do not share information about user traffic. When the same entity operates both the relay and mint, or when operators collude, they can correlate encrypted traffic patterns with mint operations, completely undermining the privacy benefits of OHTTP. - Mints MUST publish valid OHTTP key configurations and rotate them as needed per the OHTTP specification. - Wallets SHOULD validate URLs derived from mint info to avoid SSRF or downgrade attacks. If both direct HTTP and OHTTP are available, wallets SHOULD prefer OHTTP when a relay/gateway is configured and keys can be fetched successfully. From edddb7a4ccd1655cb10b204104f354d9a960eb81 Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Fri, 12 Sep 2025 12:01:43 +0100 Subject: [PATCH 3/4] chore: prettier --- 26.md | 1 - 1 file changed, 1 deletion(-) diff --git a/26.md b/26.md index ed48301a..e83f55e5 100644 --- a/26.md +++ b/26.md @@ -1,4 +1,3 @@ - # NUT-26: OHTTP Transport for Mint APIs `optional` From 2aa6b0032745f2f0c3076f1c7d11e0036c0a662a Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Fri, 12 Sep 2025 16:56:34 +0100 Subject: [PATCH 4/4] chore: relay url --- 26.md | 87 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/26.md b/26.md index e83f55e5..5234a122 100644 --- a/26.md +++ b/26.md @@ -18,27 +18,6 @@ This NUT does not change any existing Cashu API semantics. It only defines disco For optimal privacy, the relay and mint SHOULD be operated by different entities that do not collude. The privacy guarantees of OHTTP depend on the relay and mint not working together to correlate user traffic patterns. -## Discovery via NUT‑06 - -Mints advertise OHTTP support in the `nuts` section of the [NUT‑06][06] `GetInfoResponse`. - -```json -"nuts": { - ..., - "26": { - "enabled": true, - "gateway_url": "https://ohttp.example.com" // optional - } -} -``` - -Fields: - -- `enabled` (bool): Set to `true` when the mint supports OHTTP. -- `gateway_url` (str|null, optional): Base URL of the OHTTP gateway to use for key discovery (and, by convention, for the OHTTP gateway endpoint). If omitted or `null`, clients SHOULD assume the gateway is available on the mint's own origin. - -Wallets SHOULD treat `gateway_url` as a hint for where to fetch OHTTP keys. A mint MAY operate the gateway on the same origin as the mint API, in which case `gateway_url` can be omitted. - ## Gateway Endpoints A gateway MUST expose the following endpoint: @@ -49,18 +28,54 @@ A gateway MUST expose the following endpoint: - Response content type: `message/ohttp-res` - Body: opaque binary as defined by OHTTP -The GET method returns the OHTTP key configuration with content type `application/ohttp-keys` as specified in RFC 9540. +The GET method returns the OHTTP key configuration with content type `application/ohttp-keys` as specified in [RFC 9458](https://www.rfc-editor.org/rfc/rfc9458). + +## Gateway Purpose Discovery + +Gateways that support Cashu over OHTTP MUST implement a purpose discovery mechanism so clients can verify Cashu support before use. Wallets MUST verify the presence of the Cashu purpose via this mechanism before using an OHTTP gateway for Cashu operations. + +### Gateway Requirements + +Gateways MUST: + +1. Endpoint support: Respond to GET requests at `/.well-known/ohttp-gateway` when the `allowed_purposes` query parameter is present +2. Content-Type: Return `application/x-ohttp-allowed-purposes` as the Content-Type header +3. Encoding: Encode the purpose list using ALPN ProtocolNameList format (a sequence of length‑prefixed strings; each name is a 1‑byte length followed by that many UTF‑8 bytes) +4. Magic string: Include the exact Cashu purpose string: `Cashu 2253f530-151f-4800-a58e-c852a8dc8cff` + +Wire format example (single purpose): + +- Body bytes: `0x2a || "Cashu 2253f530-151f-4800-a58e-c852a8dc8cff"` + - `0x2a` (42 decimal) is the length of the ASCII string that follows -A deployment MAY route additional paths to the same handler (e.g., a catch‑all that accepts `message/ohttp-req`); clients MUST NOT rely on nonstandard paths. +### Example + +Request: + +```http +GET /.well-known/ohttp-gateway?allowed_purposes HTTP/1.1 +Host: gateway.example.com +``` + +Cashu-supporting gateway response: + +```http +HTTP/1.1 200 OK +Content-Type: application/x-ohttp-allowed-purposes + + +``` ## Client Behavior -- Key fetch: Wallets fetch the OHTTP key configuration from `gateway_url + "/.well-known/ohttp-gateway"` using a GET request. If `gateway_url` is not provided, wallets SHOULD fetch from the mint origin at `"/.well-known/ohttp-gateway"`. +- TLS: Wallets MUST use HTTPS and perform standard certificate validation when fetching OHTTP key configuration and when sending encapsulated requests to the gateway. +- URL resolution: If `gateway_url` is omitted in NUT‑06, wallets SHOULD assume the gateway endpoint is available on the mint’s origin at `/.well-known/ohttp-gateway`. +- Key consistency: Wallets SHOULD implement key consistency checks as described in the Privacy Pass Key Consistency draft to detect potential key attacks. See [draft-ietf-privacypass-key-consistency-01](https://datatracker.ietf.org/doc/html/draft-ietf-privacypass-key-consistency-01). A mechanism analogous to certificate transparency logs may be specified in future extensions for both OHTTP keys and Cashu token public keys. - Encapsulation: Wallets construct a BHTTP request ([RFC 9292](https://www.rfc-editor.org/info/rfc9292)) that mirrors a normal Cashu API call (method, scheme, authority, path, headers, and body), encapsulate it with the fetched key config, and send it to the OHTTP gateway endpoint at `"/.well-known/ohttp-gateway"` through a relay. - Headers: Wallets include the same application‑level headers they would send directly to the mint (e.g., auth headers if applicable). The gateway forwards headers to the mint backend. - Paths: The BHTTP request path is the regular Cashu API path (e.g., `/v1/mint/quote/bolt11`, `/v1/melt/bolt11`, `/v1/swap`, etc.). The gateway forwards the request to the mint backend preserving method, path, headers, and body. -Wallets MUST send OHTTP messages through a relay to the gateway. +Wallets MUST send OHTTP messages through a relay to the gateway. Direct‑to‑gateway use defeats unlinkability between client and mint and is out of scope for this NUT. ## Errors @@ -76,7 +91,29 @@ Since request/response bodies are OHTTP‑encapsulated, application‑level Cash - OHTTP provides network‑level unlinkability between client and mint. It does not hide application data from the gateway operator; the gateway must be trusted to forward requests without inspection or logging unless operated by the mint itself and configured for stateless processing. - **Non-Collusion Requirement**: OHTTP's privacy guarantees rely on the relay and mint not colluding (working together to deanonymize users). For this reason, the relay and mint SHOULD be operated by different entities that do not share information about user traffic. When the same entity operates both the relay and mint, or when operators collude, they can correlate encrypted traffic patterns with mint operations, completely undermining the privacy benefits of OHTTP. +- **Purpose Discovery Privacy**: The purpose discovery mechanism reveals gateway capabilities but does not compromise OHTTP privacy. Probing requests do not require authentication and do not reveal client identity. HTTPS SHOULD be used for gateway probing to prevent tampering. +- **Purpose String Uniqueness**: The UUID in the Cashu purpose string (`2253f530-151f-4800-a58e-c852a8dc8cff`) prevents accidental collisions with other protocols that may use similar purpose discovery mechanisms. - Mints MUST publish valid OHTTP key configurations and rotate them as needed per the OHTTP specification. - Wallets SHOULD validate URLs derived from mint info to avoid SSRF or downgrade attacks. If both direct HTTP and OHTTP are available, wallets SHOULD prefer OHTTP when a relay/gateway is configured and keys can be fetched successfully. +## Mint info setting + +Mints advertise OHTTP support in the `nuts` section of the [NUT‑06][06] `GetInfoResponse`. + +```json +{ + "nuts": { + "26": { + "supported": true, + "gateway_url": "https://ohttp.example.com" + } + } +} +``` + +Fields: + +- `supported` (bool): Set to `true` when the mint supports OHTTP. +- `gateway_url` (str|null, optional): Base URL of the OHTTP gateway to use for key discovery (and, by convention, for the OHTTP gateway endpoint). If omitted or `null`, clients SHOULD assume the gateway is available on the mint's own origin. + [06]: 06.md