mirror of
https://github.com/bitcoin/bips.git
synced 2025-06-30 12:42:43 +00:00
737 lines
32 KiB
Markdown
737 lines
32 KiB
Markdown
```
|
||
BIP: 77
|
||
Layer: Applications
|
||
Title: Async Payjoin
|
||
Author: Dan Gould <d@ngould.dev>
|
||
Yuval Kogman <nothingmuch@woobling.org>
|
||
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0077
|
||
Post-History: https://github.com/bitcoin/bips/pull/1483
|
||
https://gnusha.org/pi/bitcoindev/7B11AE34-27A7-46ED-95BF-66CA13BA26F3@ngould.dev/#t
|
||
https://gnusha.org/pi/bitcoindev/3C0A6E4C-444E-4E75-829C-1A21D8EE40E0@ngould.dev/#t
|
||
Status: Draft
|
||
Type: Standards Track
|
||
Created: 2023-08-08
|
||
License: BSD-2-Clause
|
||
Requires: 21, 78, 173, 174
|
||
```
|
||
|
||
## Copyright
|
||
|
||
This BIP is licensed under the 2-clause BSD license.
|
||
|
||
## Abstract
|
||
|
||
Payjoin lets Bitcoin senders and receivers interact to make batched
|
||
transactions.
|
||
|
||
This document proposes a second, backwards-compatible, asynchronous version of
|
||
the Payjoin protocol ("Version 2") relative to and described in [BIP 78](bip-0078.mediawiki) ("Version 1"). An untrusted
|
||
third-party "directory server" replaces the requirement
|
||
for a receiver to host a secure public endpoint for interactions. HTTP clients
|
||
access the directory server using an asynchronous protocol and authenticated,
|
||
encrypted payloads. The design preserves complete Payjoin receiver
|
||
functionality, including payment
|
||
output substitution. Authenticated encryption depends only on cryptographic
|
||
primitives available in Bitcoin Core. Requests use [Oblivious
|
||
HTTP](https://www.ietf.org/rfc/rfc9458.html) (OHTTP) to
|
||
prevent the directory and other Payjoin clients from linking requests to client
|
||
IP addresses.
|
||
|
||
## Motivation
|
||
|
||
Satoshi Nakamoto pointed out one specific privacy risk in the
|
||
[whitepaper](https://bitcoin.org/en/bitcoin-paper),
|
||
that transactions with multiple inputs "necessarily reveal that
|
||
their inputs were owned by the same owner."
|
||
Payjoin addresses that risk, the _common-input-ownership heuristic_,
|
||
by making it practical to spend inputs owned by multiple parties
|
||
in one transaction.
|
||
|
||
While addressing Bitcoin's primal privacy risk, Payjoin *input* batching
|
||
also improves on the widespread non-interactive *output* batching practice
|
||
deployed by exchanges. When combined, the same movement of funds can use
|
||
less block weight and save fees.
|
||
|
||
A natural application of Payjoin would be to combine
|
||
getting paid with consolidating UTXOs into one transaction. But Payjoin
|
||
can also secure [transaction
|
||
cut-through](https://bitcointalk.org/index.php?topic=281848.0),
|
||
allowing a sender to transfer funds to a receiver who also transfers
|
||
funds to a third party in the same transaction. For example, deposits to an
|
||
exchange may "cut through" in a single transaction that also satisfies
|
||
withdrawals instead of with a second transaction that spends the deposited
|
||
funds. Payjoin enables more blockspace-efficient transactions that
|
||
reduce fees while addressing privacy risks.
|
||
|
||
However, BIP 78's requirements for Payjoin Version 1 have proven to be an
|
||
obstacle to adoption. Version 1 receivers must host a secured
|
||
public-facing HTTP server. Mobile and web environments limit the ability
|
||
to fulfil such a requirement. Version 1 also requires synchronous
|
||
communication. Both sender and receiver must be online simultaneously.
|
||
Wallet developers [
|
||
regard](https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-January/018358.html)
|
||
these requirements as barriers to Payjoin adoption.
|
||
|
||
To address these limitations, our goal is to specify a practical
|
||
coordination mechanism suitable for widespread implementation. This proposal
|
||
leverages mature solutions to common problems, building on established web
|
||
standards and proven Bitcoin primitives.
|
||
|
||
## Overview
|
||
|
||
A Payjoin *sender* and *receiver* interact so that they may both contribute to a
|
||
transaction. In this proposal, they exchange asynchronous end-to-end
|
||
encrypted messages by relaying them to a store-and-forward *directory* server
|
||
using OHTTP.
|
||
|
||
Before initiating the protocol, the receiver must secure communications with
|
||
the directory by [bootstrapping](#ohttp-bootstrapping).
|
||
|
||
- The receiver [initiates a Payjoin Session](#session-initiation)
|
||
by sharing a [Payjoin URI](#payjoin-uri) that includes the URL of an
|
||
ephemeral mailbox hosted on the directory, where it can receive a message
|
||
from the sender.
|
||
- The sender [posts a message](#sender-original-psbt-messaging)
|
||
containing a fully signed fallback transaction, known as the *Original PSBT*,
|
||
to the mailbox.
|
||
- The receiver gets this message and
|
||
[posts a message containing a *Proposal
|
||
PSBT*](#receiver-proposal-psbt-messaging)
|
||
to the sender's ephemeral mailbox, by updating the Original PSBT with
|
||
appropriate inputs and/or outputs.
|
||
- The sender gets the Proposal PSBT, [checks it, signs, and
|
||
broadcasts](#sender-signing-and-broadcast) the final transaction.
|
||
|
||
At any point, either party may choose to broadcast the
|
||
fallback transaction described by the Original PSBT instead of proceeding.
|
||
Because the Original PSBT and Proposal PSBT spend the same input(s) they are
|
||
mutually exclusive and only one can be confirmed.
|
||
|
||
Messages are buffered in the directory, allowing both parties to tolerate
|
||
temporary disconnections and resume communication by polling.
|
||
|
||
### Sequence Diagram
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
title Async Payjoin Sequence Diagram
|
||
participant R as Receiver
|
||
participant D as Directory
|
||
participant S as Sender
|
||
participant N as Network
|
||
|
||
R-)S: Payjoin URI (BIP 21) out of band
|
||
|
||
R-->>D: Poll GET Requests<br/>for Original PSBT
|
||
activate D
|
||
S->>D: POST Request<br/>Original PSBT
|
||
D->>R: GET Response<br/>Original PSBT
|
||
deactivate D
|
||
|
||
S-->>D: Poll GET Requests<br/>for Proposal PSBT
|
||
activate D
|
||
R->>D: POST Request<br/>Proposal PSBT
|
||
D->>S: GET Response<br/>Proposal PSBT
|
||
deactivate D
|
||
|
||
S->>N: Broadcast Payjoin
|
||
```
|
||
|
||
## Specification
|
||
|
||
### OHTTP Bootstrapping
|
||
|
||
Before initiating a Payjoin Session a receiver must first discover the
|
||
directory's
|
||
[OHTTP Key Configuration](https://www.ietf.org/rfc/rfc9458.html#section-3.1),
|
||
via an authenticated
|
||
bootstrap mechanism. The key configuration contains information to establish
|
||
[Hybrid Public Key Encryption](#secp256k1-hybrid-public-key-encryption) (HPKE) in order to secure communications between the client and the directory in
|
||
lieu of TLS.
|
||
|
||
The bootstrap mechanism may vary by implementation but must
|
||
follow [OHTTP Consistency
|
||
Requirements](https://datatracker.ietf.org/doc/html/draft-ietf-privacypass-key-consistency-01)
|
||
and should not reveal a receiver IP address to the directory. Some
|
||
examples of suitable mechanisms include getting a key configuration
|
||
from a Payjoin URI, a trusted application binary, or fetching using https-in-http
|
||
CONNECT method, https-in-WebSocket, Tor, or a VPN.
|
||
|
||
Directory OHTTP Gateways MUST support [RFC 9540 Key Configuration
|
||
Fetching](https://www.rfc-editor.org/rfc/rfc9540.html#name-key-configuration-fetching)
|
||
via GET request. RFC 9540 defines the
|
||
gateway location as `/.well-known/ohttp-gateway`.
|
||
|
||
### Session Initiation
|
||
|
||
A receiver initiates a session by sharing a Payjoin URI. Because a URI
|
||
contains sensitive information, such as a receiver address, it should be shared
|
||
over a confidential channel.
|
||
|
||
#### Payjoin URI
|
||
|
||
Bitcoin URIs ([BIP
|
||
21](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki)
|
||
or [BIP
|
||
321](https://github.com/bitcoin/bips/blob/master/bip-0321.mediawiki))
|
||
are a standard way to request bitcoin.
|
||
|
||
A Payjoin URI is a Bitcoin URI that contains a `pj` parameter. The `pj`
|
||
parameter value is a URL in both BIP 78 and BIP 77.
|
||
|
||
Senders that understand Bitcoin URI but don't support Payjoin will just
|
||
ignore the `pj` parameter and proceed to typical address-based
|
||
transaction flows.
|
||
|
||
A `req-pj` parameter may be used as a [BIP 21 forwards compatibility `reqparam`](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki#forward-compatibility) instead of
|
||
`pj` to signal that Payjoin is required.
|
||
|
||
The parameter value must be [uppercased and the parameter should be placed last in the URI](#uppercase-url).
|
||
|
||
Since BIP 78 payloads are neither encrypted nor authenticated,
|
||
a directory used for backwards-compatible payloads is known
|
||
as an ["unsecured payjoin server" in BIP 78
|
||
parlance](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#unsecured-payjoin-server).
|
||
Backwards-compatible receivers MUST disable output substitution
|
||
by setting `pjos=0` to prevent modification by a malicious directory.
|
||
|
||
##### Mailbox endpoint
|
||
|
||
In this proposal the URL in the `pj` parameter value is the mailbox
|
||
endpoint URL. Mailboxes are shared HTTP resources hosted by the
|
||
directory and serve as OHTTP Target Resources. Clients use these endpoints
|
||
to relay encrypted messages. They `POST` messages to and `GET` messages from
|
||
mailbox endpoints via OHTTP.
|
||
|
||
Senders that support BIP 78 but not this proposal may POST messages directly to
|
||
mailbox endpoints for [backwards compatibility](#backwards-compatibility).
|
||
|
||
###### Short ID
|
||
|
||
A Short ID identifies a mailbox based on its associated public key. The Short
|
||
ID is the path component of the mailbox endpoint. One is derived by hashing the
|
||
33-byte compressed public key encoding with SHA-256, truncating it to
|
||
[8 bytes (64 bits)](#64-bit-short-id-length), and encoding it in
|
||
[uppercase](#uppercase-url) using the bech32 character set (like a bech32 string without the HRP, separator and checksum).
|
||
|
||
##### Receiver fragment parameters
|
||
|
||
This proposal introduces session-specific parameters which the
|
||
receiver shares encoded in the URI.
|
||
|
||
Instead of defining new Bitcoin URI parameters, the session-specific
|
||
parameters are encoded in the [
|
||
fragment](https://datatracker.ietf.org/doc/html/rfc3986#section-3.5)
|
||
of the mailbox endpoint URL.
|
||
|
||
The `#` fragment separator character must be [RFC 3986
|
||
percent-encoded](https://datatracker.ietf.org/doc/html/rfc3986#section-2.1)
|
||
as `%23`, because it separates the
|
||
fragment of the mailbox endpoint URL included in the `pj` parameter, not the
|
||
fragment of the Bitcoin URI.
|
||
|
||
These session-specific parameters use a bech32-inspired encoding.
|
||
The HRP is used as the parameter key, followed by the '1' separator,
|
||
followed by the parameter value encoded using the bech32 character set in
|
||
[uppercase](#uppercase-url). No checksum is used. Parameters are separated
|
||
by a `+` character.
|
||
|
||
The following parameters are defined, and must be provided in reverse
|
||
lexicographical order:
|
||
|
||
- `RK`: encodes the *receiver key* as a 33-byte compressed public key.
|
||
Senders will initiate HPKE with the receiver using this key.
|
||
- `OH`: encodes an alternate format of the OHTTP Key Configuration of
|
||
the directory. It consists of a 33-byte compressed public key of the
|
||
directory's OHTTP Gateway, prefixed by the 2-byte Key Identifier. A [
|
||
RFC 9458 Key
|
||
Configuration](https://www.ietf.org/rfc/rfc9458.html#section-3.1)
|
||
is reconstructed by assuming the HPKE KEM ID and Symmetric Algorithms
|
||
are [fixed](#secp256k1-hybrid-public-key-encryption).
|
||
- `EX`: specifies a [session
|
||
expiration](#session-expiration) in [unix
|
||
time](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16).
|
||
|
||
For example, a properly encoded endpoint Bitcoin URI looks like this
|
||
`bitcoin:tb1q6q6de88mj8qkg0q5lupmpfexwnqjsr4d2gvx2p?amount=0.00666666&pjos=0&pj=HTTPS://PAYJO.IN/TXJCGKTKXLUUZ%23RK1Q0DJS3VVDXWQQTLQ8022QGXSX7ML9PHZ6EDSF6AKEWQG758JPS2EV+OH1QYPM59NK2LXXS4890SUAXXYT25Z2VAPHP0X7YEYCJXGWAG6UG9ZU6NQ+EX1WKV8CEC`
|
||
|
||
### Sender Original PSBT Messaging
|
||
|
||
The sender constructs the fallback transaction, a typical transaction
|
||
spending funds to the receiver's address specified in the Payjoin URI.
|
||
This transaction is serialized as a BIP 174 PSBTv0, satisfying
|
||
[the receiver checklist](#receivers-original-psbt-checklist).
|
||
|
||
The Original PSBT MUST:
|
||
|
||
- Include complete UTXO data.
|
||
- Be fully signed.
|
||
- Exclude unnecessary fields such as global xpubs or keypath
|
||
information.
|
||
- Be broadcastable.
|
||
|
||
The Original PSBT MAY:
|
||
|
||
- Include outputs unrelated to the sender-receiver transfer for batching
|
||
purposes.
|
||
|
||
This *Original PSBT* is encoded as base64, followed by the query
|
||
parameter string on a new line containing [optional sender
|
||
parameters](#optional-sender-parameters).
|
||
|
||
The sender generates an ephemeral mailbox key. The corresponding public key is
|
||
known as the *reply key*, and it is prepended to the base64 plaintext string,
|
||
serialized in compressed form as 33 bytes.
|
||
|
||
This plaintext string is encrypted to the receiver key according to [HPKE Base
|
||
mode](https://www.rfc-editor.org/rfc/rfc9180.html#name-encryption-to-a-public-key).
|
||
The HPKE `info` string, used for domain separation, is `PjV2MsgA`. The
|
||
ciphertext ensures message secrecy and integrity when passed to the receiver
|
||
using the mailbox endpoint. The 16-byte authentication tag is appended to the
|
||
ciphertext.
|
||
|
||
RFC 9180 [does not
|
||
specify](https://www.rfc-editor.org/rfc/rfc9180.html#section-10) the wire format
|
||
encoding of HPKE messages. To construct an HPKE payload, the secp256k1 public
|
||
key from the DHKEM is encoded using ElligatorSwift in 64 bytes. Note that
|
||
ElligatorSwift is only the wire format; when deriving shared secrets, the curve
|
||
point is re-serialized in uncompressed form.
|
||
|
||
```
|
||
PjV2MsgA Byte Representation (7168 bytes total)
|
||
+---------------------------------------------------------------------------------------+
|
||
| ElligatorSwift | Ciphertext |
|
||
| (64 bytes) | (7104 bytes) |
|
||
| +-----------------------+---------------------------------+------------+
|
||
| | Reply Key | Padded Plaintext | AEAD Tag |
|
||
| | (33 bytes) | (7055 bytes = 7168-64-33-16) | (16 bytes) |
|
||
+---------------------------------------------------------------------------------------+
|
||
```
|
||
|
||
The resulting HPKE payload is the body of a POST request to the
|
||
receiver's mailbox. This request is then [
|
||
encapsulated](#client-directory-interactions) according to
|
||
Oblivious HTTP to the directory's OHTTP Gateway. OHTTP serializes the
|
||
inner request as BHTTP, and provides another layer of HPKE encryption,
|
||
between the client and directory.
|
||
|
||
Upon receipt, the directory's OHTTP Gateway decapsulates the OHTTP
|
||
request and handles the inner POST request at the receiver's mailbox
|
||
endpoint, which stores the HPKE encrypted payload to be forwarded to the
|
||
receiver.
|
||
|
||
The sender then polls OHTTP encapsulated GET requests to the sender's
|
||
mailbox endpoint until it receives a response from the directory
|
||
containing the receiver's *Proposal PSBT*, and proceeds to
|
||
[sign and broadcast](#sender-signing-and-broadcast).
|
||
It stops polling after expiration.
|
||
|
||
#### Optional sender parameters
|
||
|
||
[BIP 78's optional sender parameters](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#optional-parameters)
|
||
may be used in this proposal, but must be included in
|
||
the body as part of the ciphertext rather than as a query string.
|
||
|
||
HPKE binds ciphertexts to application-specific `info` strings. Because
|
||
of this domain separation, BIP 78's `v` parameter is redundant and
|
||
should be omitted for this proposal.
|
||
|
||
### Receiver Proposal PSBT Messaging
|
||
|
||
After sharing the Payjoin URI with the sender, the receiver polls via
|
||
OHTTP encapsulated GET requests to the receiver's mailbox endpoint. So
|
||
long as the mailbox contains no message, the directory responds with
|
||
status 202 ACCEPTED. Once a mailbox contains a message, the directory
|
||
returns it in the response body with status 200 OK.
|
||
|
||
Upon receiving an encapsulated 200 OK response, the receiver decrypts
|
||
the payload and checks the *Original PSBT* therein according to the
|
||
[receiver checklist](#receivers-original-psbt-checklist).
|
||
|
||
The receiver then updates the *Original PSBT* to include new signed
|
||
inputs and outputs, invalidating the sender's signature(s). The receiver
|
||
may also adjust the transaction fee. The result, called the *Proposal
|
||
PSBT*, must satisfy the [sender checklist](#senders-proposal-psbt-checklist)
|
||
|
||
The Proposal PSBT MUST:
|
||
|
||
- Include complete UTXO data.
|
||
- Include all inputs from the Original PSBT.
|
||
- Include all outputs which do not belong to the receiver from the
|
||
Original PSBT.
|
||
- Use a random index if additional inputs or outputs are added.
|
||
|
||
The Proposal PSBT sender MAY:
|
||
|
||
- Add inputs at random indices.
|
||
- Add outputs at random indices.
|
||
- Remove or modify Original PSBT outputs under the control of the
|
||
receiver (i.e. not sender change).
|
||
|
||
The Proposal PSBT MUST NOT:
|
||
|
||
- Shuffle the order of inputs or outputs contained in the Original PSBT.
|
||
- Decrease the absolute fee of the Original PSBT.
|
||
|
||
The receiver encrypts the *Proposal PSBT* to the sender's reply key according to
|
||
[HPKE Auth
|
||
mode](https://www.rfc-editor.org/rfc/rfc9180.html#name-authentication-using-an-asy),
|
||
using the receiver's key for authentication. The HPKE `info` string is
|
||
`PjV2MsgB`. The HPKE wire format is the same as in the [sender's
|
||
message](#sender-original-psbt-messaging).
|
||
|
||
```
|
||
PjV2MsgB Byte Representation (7168 bytes total)
|
||
+---------------------------------------------------------------------------------------+
|
||
| ElligatorSwift | Ciphertext |
|
||
| (64 bytes) | (7104 bytes) |
|
||
| +---------------------------------------------------------+------------+
|
||
| | Padded Plaintext | AEAD Tag |
|
||
| | (7088 bytes = 7168-64-16) | (16 bytes) |
|
||
+---------------------------------------------------------------------------------------+
|
||
```
|
||
|
||
The receiver makes the resulting HPKE payload the body of a POST request to the
|
||
sender's mailbox whose Short ID is derived from the sender's reply key. This request is then [
|
||
encapsulated](#client-directory-interactions) according to
|
||
Oblivious HTTP to the directory's OHTTP Gateway. OHTTP serializes the
|
||
inner request as BHTTP, and provides another layer of HPKE encryption,
|
||
between the client and directory.
|
||
|
||
Once the receiver makes this request, they wait for either transaction from the
|
||
Original PSBT or Proposal PSBT to be broadcast to the Bitcoin network.
|
||
|
||
#### Receiver's Original PSBT checklist
|
||
|
||
The receiver checklist is the same as [the BIP 78 receiver
|
||
checklist](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-original-psbt-checklist).
|
||
|
||
### Sender signing and broadcast
|
||
|
||
The sender validates the *Proposal PSBT* it receives against a
|
||
checklist. If the checks pass, it may sign and broadcast the resulting
|
||
Payjoin transaction.
|
||
|
||
#### Sender's Proposal PSBT checklist
|
||
|
||
This proposal's sender checklist is the same as [the BIP 78 sender
|
||
checklist](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#senders-payjoin-proposal-checklist).
|
||
|
||
### Client/Directory interactions
|
||
|
||
The Payjoin Directory provides a rendezvous point for senders and
|
||
receivers to exchange messages. The directory stores Payjoin payloads to
|
||
support asynchronous communication. Async Payjoin requests must be
|
||
submitted as encapsulated messages to the directory's OHTTP Gateway.
|
||
|
||
The wire format OHTTP request is specified in [RFC
|
||
9458](https://www.ietf.org/rfc/rfc9458.html#name-hpke-encapsulation). HPKE
|
||
requires the directory's OHTTP key configuration. The plaintext is a binary
|
||
encoded HTTP request ([RFC 9292](https://www.rfc-editor.org/rfc/rfc9292.html))
|
||
intended for the OHTTP target resource, usually a mailbox endpoint, padded to
|
||
8104 bytes with [random data](#random-padding).
|
||
|
||
```
|
||
OHTTP Encapsulated Request Byte Representation (8192 bytes total)
|
||
+--------------+-------------------------+------------------------------------------+
|
||
| OHTTP Header | HPKE KEM | Ciphertext |
|
||
| (7 bytes) | Uncompressed Public Key | (8120 bytes = 8192-65-7) +
|
||
| | (65 bytes) +-----------------------------+------------+
|
||
| | | Padded BHTTP Request | AEAD Tag |
|
||
| | | (8104 bytes = 8192-65-16-7) | (16 bytes) |
|
||
+--------------+-------------------------+------------------------------------------+
|
||
```
|
||
|
||
Response encryption uses the Export functionality of the request HPKE context to
|
||
establish a shared secret, and therefore consists of a 32 byte nonce followed by
|
||
the AEAD ciphertext and tag.
|
||
|
||
```
|
||
OHTTP Encapsulated Response Byte Representation (8192 bytes total)
|
||
+---------------------+------------------------------------------+
|
||
| Nonce | Ciphertext |
|
||
| (32 bytes) | (8160 bytes = 8192-32) +
|
||
| +-----------------------------+------------+
|
||
| | Padded BHTTP Response | AEAD Tag |
|
||
| | (8144 bytes = 8192-32-16) | (16 bytes) |
|
||
+---------------------+------------------------------------------+
|
||
```
|
||
|
||
GET requests on an empty mailbox should block until a message is posted
|
||
or a timeout occurs. The timeout should be 30 seconds because that will
|
||
not exceed the default timeout for most HTTP clients.
|
||
|
||
The directory may optionally accept HTTP/1.1 POST requests without OHTTP
|
||
to mailbox endpoint URLs for backwards compatibility with BIP 78 senders.
|
||
|
||
#### OHTTP Sequence Diagram
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
title OHTTP Sequence Diagram
|
||
participant C as Client
|
||
participant R as OHTTP Relay
|
||
|
||
box PaleVioletRed Payjoin Directory
|
||
participant G as OHTTP Gateway
|
||
participant D as HTTP Resource
|
||
end
|
||
|
||
C->>R: Relay Request<br/>FROM: Client IP<br/>[+ Encapsulated Request]
|
||
R->>G: Gateway Request<br/>FROM: Relay IP<br/>[+ Encapsulated Request]
|
||
G->>D: Request
|
||
D->>G: Response
|
||
G->>R: Gateway Response<br/>TO: Relay IP<br/>[+ Encapsulated Response]
|
||
R->>C: Relay Response<br/>TO: Client IP<br/>[+ Encapsulated Response]
|
||
```
|
||
|
||
### Relay/Directory interactions
|
||
|
||
RFC 9458 requires each OHTTP Relay to be configured to forward requests
|
||
to exactly one OHTTP Gateway. This requirement prevents receivers from
|
||
being able to choose any directory, and senders from choosing relays
|
||
independently. Without addressing this limitation, senders would have to
|
||
know which relays are appropriate to use for each directory, creating a
|
||
tendency for one directory and its affiliated relays to monopolize the
|
||
protocol.
|
||
|
||
In order to allow OHTTP Relays to be used with any directory, a
|
||
directory's OHTTP Gateway may advertise this allowed purpose. This
|
||
advertisement prevents OHTTP Relays from acting as open internet proxies,
|
||
which would otherwise allow anonymized access to arbitrary resources and
|
||
expose them to denial-of-service attacks, as well as other forms of abuse.
|
||
When the directory receives a GET request to the `/.well-known/ohttp-gateway`
|
||
path with an `allowed_purposes` query parameter, its response body
|
||
should contain a magic string in the same format as a TLS ALPN protocol
|
||
list (a U16BE length encoded list of U8 length encoded strings). The
|
||
magic string is `BIP77 454403bb-9f7b-4385-b31f-acd2dae20b7e`, offering
|
||
an unambiguous signal to relays that this OHTTP Gateway will accept
|
||
requests associated with this purpose from any relay.
|
||
|
||
By supporting this `allowed_purposes` parameter, the directory signals
|
||
to OHTTP Relays that it is willing to handle requests related to BIP 77,
|
||
removing the RFC 9458's requirement that relays and
|
||
Gateways be configured in a one-to-one relationship.
|
||
|
||
## Rationale
|
||
|
||
### Uppercase URL
|
||
|
||
In order to simplify parsing and allow QR encoders to use [Alphanumeric
|
||
QR
|
||
mode](https://www.rfc-editor.org/rfc/rfc9285.html#name-the-alphabet-used-in-base45),
|
||
which is more compact than Byte mode, the mailbox endpoint URL,
|
||
including the fragment parameters, is encoded in uppercase.
|
||
|
||
Unlike Bitcoin URI parameters, which require switching back to Byte
|
||
mode, the use of the URL fragment for session-specific parameters makes
|
||
it possible to stay in Alphanumeric mode.
|
||
|
||
### Parameter Ordering
|
||
|
||
The order of fragment parameters, Bitcoin URI parameters, as well as in the
|
||
sender's optional parameters have no defined meaning.
|
||
|
||
In the BIP 21 URI, the `pj` parameter mailbox endpoint URL SHOULD be the last
|
||
parameter to avoid QR mode switching.
|
||
|
||
Since variations might create a fingerprint for particular wallet software,
|
||
this document requires that fragment parameters MUST appear in reverse
|
||
lexicographical order.
|
||
|
||
### Session Expiration
|
||
|
||
The directory may hold a message for an offline Payjoin client until that
|
||
client comes online. However, the BIP 78 spec [
|
||
recommends](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receiver-does-not-need-to-be-a-full-node)
|
||
broadcasting Original PSBTs in the case of an offline counterparty.
|
||
Doing so exposes a naïve, surveillance-vulnerable transaction, which
|
||
Payjoin intends to avoid.
|
||
|
||
Because BIP 78 is a synchronous protocol without a standard expiration
|
||
mechanism, and automated receivers are vulnerable to probing attacks,
|
||
BIP 78 encourages receivers to broadcast the Original PSBT after some
|
||
undefined expiration time.
|
||
|
||
Because BIP 77 is an asynchronous protocol, it requires an explicit [
|
||
session-specific fragment
|
||
parameter](#receiver-fragment-parameters), `EX`, to
|
||
communicate this expiration time to the sender.
|
||
|
||
There is no way for a sender to prevent a receiver from broadcasting the
|
||
fallback transaction extracted from the Original PSBT before the
|
||
receiver-specified expiration time.
|
||
|
||
### 64-bit Short ID Length
|
||
|
||
64 bits are sufficient to make the probability of experiencing a random
|
||
collision negligible. As of writing, the UTXO set has ~2^28 elements.
|
||
This is a very loose upper bound for the number of concurrent (non-spam)
|
||
sessions, for which the probability of a random collision will be less
|
||
than 1%. The actual number of sessions will of course be (orders of
|
||
magnitudes) lower given that sessions are short-lived. With ~2^21
|
||
sessions (a loose bound on number of transactions that can be confirmed
|
||
in 24 hours) the probability is less than 1e-6. These figures bound the
|
||
probability of a collision existing anywhere in the entire set, whereas
|
||
the probability for an individual session to experience a collision is
|
||
\<\< 1e-10 in either case.
|
||
|
||
### Complete UTXO Data
|
||
|
||
Complete UTXO data is required because this information is required for
|
||
signing and calculating fees for some input types.
|
||
|
||
### HTTP
|
||
|
||
HTTP is ubiquitous. Using simple HTTP polling allows even Bitcoin Core
|
||
to consider an implementation. Unlike a WebSockets protocol, plain HTTP
|
||
can benefit from metadata protection by using Oblivious HTTP.
|
||
|
||
### Oblivious HTTP
|
||
|
||
OHTTP protects sender and receiver IP addresses both from one another
|
||
and from the directory. This makes it more difficult for a directory to
|
||
correlate many Payjoin transactions with specific IP addresses.
|
||
|
||
OHTTP relays can be run as basic HTTP proxies from wallet providers or
|
||
third parties.
|
||
|
||
### Uniform Payloads
|
||
|
||
Encapsulated OHTTP payloads seen by the relay and directory, and
|
||
encrypted messages seen by the directory, are constructed to be uniform
|
||
so that these third-party services are unable to distinguish between
|
||
them.
|
||
|
||
Encapsulated OHTTP messages are 8192 bytes long, and begin with a
|
||
cleartext OHTTP header and an uncompressed key which is distinguishable
|
||
from random bytes but uniform across different encapsulated requests.
|
||
|
||
End-to-end encrypted messages are 7168 bytes long, and should be
|
||
indistinguishable from uniformly random bytes.
|
||
[ElligatorSwift as defined in BIP 324](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki#elligatorswift-encoding-of-curve-x-coordinates)
|
||
is used to encode encapsulated HPKE public keys prepended to the HPKE ciphertext
|
||
so that the directory can't distinguish between key material, the
|
||
ciphertext, and randomness. This ensures the two different protocol
|
||
messages are indistinguishable from each other as well as any protocol
|
||
extensions.
|
||
|
||
These padded sizes are sufficient for most PSBTs without exceeding the [
|
||
8KB
|
||
limit](https://www.geekersdigest.com/max-http-request-header-size-server-comparison/)
|
||
of many HTTP/1.1 web servers. 8KB is also too small for image sharing,
|
||
making misuse of the directory impractical.
|
||
|
||
#### Random Padding
|
||
|
||
The typical [zero padding recommended by the BHTTP
|
||
specification](https://www.rfc-editor.org/rfc/rfc9292.html#name-padding-and-truncation)
|
||
would make future use of [multi-hop OHTTP inspired by the Sphinx mix
|
||
format](https://github.com/orgs/payjoin/discussions/582) detectable from the
|
||
point of view of the directory. Random padding is allowed so long as the BHTTP
|
||
encoded request is not truncated.
|
||
|
||
By randomly padding OHTTP messages, any future use of such techniques would be
|
||
indistinguishable from clients that only implement standardized OHTTP. Since
|
||
this would limit a malicious directory's ability to censor any such requests in
|
||
the future, and such requests significantly bolster the privacy threat model
|
||
against malicious OHTTP relays or traffic analysis by a global passive
|
||
adversary, it is desirable to do so for standard OHTTP requests as well.
|
||
|
||
### Secp256k1 Hybrid Public Key Encryption
|
||
|
||
[RFC 9180 Hybrid Public Key
|
||
Encryption](https://www.rfc-editor.org/rfc/rfc9180.html)
|
||
(HPKE) is a modern IETF standard for secure
|
||
message exchange without TLS, since TLS is not available in Bitcoin Core.
|
||
|
||
This proposal uses `DHKEM(Secp256k1, HKDF-SHA256)` and
|
||
`ChaCha20Poly1305` AEAD for both OHTTP encapsulation and for end-to-end
|
||
encryption between the sender and receiver.
|
||
|
||
The receiver transmits its receiver key in [receiver fragment
|
||
parameters](#receiver-fragment-parameters). The sender shares
|
||
its reply key along with the Original PSBT. These keys are ephemeral and
|
||
must only be used for a single Payjoin Session.
|
||
|
||
#### Secp256k1-based DHKEM
|
||
|
||
[Secp256k1-based DHKEM for
|
||
HPKE](https://www.ietf.org/archive/id/draft-wahby-cfrg-hpke-kem-secp256k1-01.html)
|
||
is most appropriate because of secp256k1's availability in bitcoin
|
||
contexts.
|
||
|
||
#### ChaCha20Poly1305 AEAD
|
||
|
||
This authenticated encryption with additional data [
|
||
algorithm](https://en.wikipedia.org/wiki/ChaCha20-Poly1305)
|
||
is standardized in [RFC
|
||
8439](https://www.rfc-editor.org/rfc/rfc8439) and has high
|
||
performance. ChaCha20Poly1305 AEAD has been implemented [in Bitcoin
|
||
Core](https://github.com/bitcoin/bitcoin/pull/15649) for [
|
||
BIP 324 Encrypted
|
||
Transport](https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki)
|
||
as well. This has widespread support in browsers and common
|
||
cryptographic libraries. AES-GCM is more widespread but slower without
|
||
hardware support and not typically already a dependency in bitcoin software.
|
||
|
||
#### HKDF-SHA256
|
||
|
||
SHA-256 is necessarily available in bitcoin contexts.
|
||
|
||
## Attack vectors
|
||
|
||
In addition to the attack vectors and mitigations in
|
||
[BIP 78](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#attack-vectors),
|
||
this proposal has the following attack vectors.
|
||
|
||
### Directory Denial of Service
|
||
|
||
Since each mailbox stores arbitrary encrypted payloads, directories are
|
||
vulnerable to flooding. To mitigate such denial of service attacks,
|
||
directory operators may respond with `401` unauthorized unless an
|
||
authorization token is provided. Authorization tokens must be unlinkable
|
||
to preserve client privacy. A specific unlinkable authorization token
|
||
mechanism is out of the scope of this proposal.
|
||
|
||
### Network privacy
|
||
|
||
Oblivious HTTP must be used to protect the IP addresses of both sender
|
||
and receiver from the directory. This requires an OHTTP Key
|
||
Configuration to be shared in the Payjoin URI and for the directory to
|
||
support Oblivious HTTP.
|
||
|
||
Unlike BIP 78 implementations, sender and receiver clients will only see
|
||
the IP address of the directory and not that of the client they are
|
||
interacting with.
|
||
|
||
Senders that submit requests directly to the directory, without using
|
||
an OHTTP Relay, may reveal their IP address to the receiver since that
|
||
receiver also specifies the directory.
|
||
|
||
## Backwards compatibility
|
||
|
||
Senders not supporting Payjoin will just ignore the `pj` parameter and
|
||
proceed to typical address-based transaction flows.
|
||
|
||
All Payjoin versions use [Bitcoin URIs](#payjoin-uri).
|
||
Receivers may choose to accept BIP 78 payloads at their discretion.
|
||
|
||
A BIP 78 sender posts their request to the directory, which stores
|
||
and forwards it to the BIP 77 receiver. A backwards-compatible
|
||
receiver proceeds with the BIP 78 checks if the encapsulated response
|
||
body is UTF-8 plaintext, signifying BIP 78. In order to service the
|
||
request, a BIP 78 response must be returned to the sender within 30
|
||
seconds or else the directory should respond with an `unavailable` JSON
|
||
error code as [defined in BIP
|
||
78](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-well-known-errors).
|
||
|
||
## Reference implementation
|
||
|
||
A production reference implementation client can be found at
|
||
<https://crates.io/crates/payjoin-cli>. Source code for the clients, the
|
||
directory, and development kit may be found here:
|
||
<https://github.com/payjoin/rust-payjoin>. Source code for an Oblivious
|
||
HTTP relay implementation may be found here:
|
||
<https://github.com/payjoin/ohttp-relay>.
|