directory -> mailbox

This commit is contained in:
DanGould
2025-03-25 12:31:04 -04:00
parent 34f66d00ba
commit a4d4065fa6

View File

@@ -19,10 +19,10 @@
This document proposes a backwards-compatible second version of the Payjoin protocol described in This document proposes a backwards-compatible second version of the Payjoin protocol described in
[[bip-0078.mediawiki|BIP 78]], allowing complete Payjoin receiver functionality, including payment output [[bip-0078.mediawiki|BIP 78]], allowing complete Payjoin receiver functionality, including payment output
substitution, without requiring a receiver to host a secure public endpoint. This requirement is replaced with an substitution, without requiring a receiver to host a secure public endpoint. This requirement is replaced with an
untrusted third-party directory accessed via HTTP clients that communicate using an asynchronous protocol untrusted third-party "mailroom" server accessed via HTTP clients that communicate using an asynchronous protocol
and authenticated, encrypted payloads. Authenticated encryption depends only on cryptographic primitives and authenticated, encrypted payloads. Authenticated encryption depends only on cryptographic primitives
available in Bitcoin Core. Requests use [[https://www.ietf.org/rfc/rfc9458.html| Oblivious HTTP]] to prevent available in Bitcoin Core. Requests use [[https://www.ietf.org/rfc/rfc9458.html| Oblivious HTTP]] to prevent
the directory and Payjoin peers from linking requests to client IP addresses. the mailroom and Payjoin peers from linking requests to client IP addresses.
==Copyright== ==Copyright==
@@ -64,13 +64,13 @@ URIs. Because BIP 78 messages relayed over an unsecured server are neither end-t
encrypted between sender and receiver, a malicious unsecured Payjoin server is able to modify the Proposal encrypted between sender and receiver, a malicious unsecured Payjoin server is able to modify the Proposal
PSBT in flight, thus requiring payment output substitution to be disabled. Output substitution is useful for PSBT in flight, thus requiring payment output substitution to be disabled. Output substitution is useful for
a number of block space optimizations, including payment batching and transaction cut-through. This proposal a number of block space optimizations, including payment batching and transaction cut-through. This proposal
introduces authentication and encryption to secure output substitution by using a directory server without introduces authentication and encryption which secure output substitution while relying on a mailbox server without
compromising sender or receiver privacy. compromising sender or receiver privacy.
Although unsecured Payjoin server separation is mentioned in BIP 78, no known specification or implementation Although unsecured Payjoin server separation is mentioned in BIP 78, no known specification or implementation
exists. This document specifies a way to use the Payjoin directory as an unsecured backwards compatible server exists. This document specifies a mailbox server as an unsecured backwards compatible server
for version 1 senders. Receivers responding to version 1 senders must disable output substitution, since their for version 1 senders. Receivers responding to version 1 senders must disable output substitution, since their
payloads are saved in plaintext, so that they may payjoin without the risk of the directory, acting as a payloads are saved in plaintext, so that they may payjoin without the risk of the mailbox server, acting as a
version 1 unsecured Payjoin server, stealing funds. version 1 unsecured Payjoin server, stealing funds.
The protocols in this document reuse BIP 78's BIP 21 URI parameters. An "Original PSBT" timeout parameter is The protocols in this document reuse BIP 78's BIP 21 URI parameters. An "Original PSBT" timeout parameter is
@@ -80,8 +80,8 @@ introduced which may also help coordinate the synchronous version 1 protocol.
[[https://docs.samourai.io/en/spend-tools#stowaway| Stowaway]] was a Payjoin coordination mechanism that [[https://docs.samourai.io/en/spend-tools#stowaway| Stowaway]] was a Payjoin coordination mechanism that
depended on Tor, a third-party relay, and the [[https://paynym.is| PayNym]] [[https://github.com/bitcoin/bips/ depended on Tor, a third-party relay, and the [[https://paynym.is| PayNym]] [[https://github.com/bitcoin/bips/
blob/master/bip-0047.mediawiki| BIP 47]] "payment codes" directory for subdirectory identification and blob/master/bip-0047.mediawiki| BIP 47]] "payment codes" server for peer identification and
encryption. The Payjoin version 2 protocol uses per-request public keys for relay subdirectory identification, encryption. The Payjoin version 2 protocol uses per-request public keys for peer identification,
authentication, and encryption instead of BIP 47 public keys derived from a wallet. Payjoin version 2 also authentication, and encryption instead of BIP 47 public keys derived from a wallet. Payjoin version 2 also
supports asynchronous messaging, in contrast to Stowaway's synchronous messaging. Offline Stowaway depends on supports asynchronous messaging, in contrast to Stowaway's synchronous messaging. Offline Stowaway depends on
manual message passing rather than an asynchronous network protocol. Successful Stowaway execution results in manual message passing rather than an asynchronous network protocol. Successful Stowaway execution results in
@@ -92,46 +92,45 @@ manual message passing rather than an asynchronous network protocol. Successful
===Overview=== ===Overview===
Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP endpoint, this scheme allows Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP endpoint, this scheme allows
an HTTP client to initiate a Payjoin Session at a store-and-forward directory server to send and receive an HTTP client to initiate a Payjoin Session at a store-and-forward mailroom server to send and receive
Payjoin messages. Directories may optionally require an authorization credential before allocating resources Payjoin messages. Mailrooms may optionally require an authorization credential before allocating resources
in order to prevent DoS attacks. Sender and receiver payloads are buffered at the directory to support in order to prevent DoS attacks. Sender and receiver payloads are buffered at the mailroom to support
asynchronous interaction. Authenticated encryption prevents the directory from snooping on message contents asynchronous interaction. Authenticated encryption prevents the mailroom from snooping on message contents
or forging messages by way of HPKE. Oblivious HTTP is required for version 2 interactions in order to separate or forging messages by way of HPKE. Oblivious HTTP is required for version 2 interactions in order to separate
client IP addresses from the directory to prevent metadata attacks. Aside from application layer authenticated client IP addresses from the mailroom to prevent metadata attacks. Aside from application layer authenticated
encryption and relayed asynchronous networking, version 2 messaging takes much the same form as the existing encryption and relayed asynchronous networking, version 2 messaging takes much the same form as the existing
BIP 78 specification. BIP 78 specification.
===Basic scheme=== ===Basic scheme===
The receiver first generates a 256-bit keypair. This key will be the basis of end-to-end authenticated The receiver first generates a 256-bit keypair. This key will be the basis of end-to-end authenticated
encryption and identification of a particular payjoin over the directory. encryption and identification of a particular mailbox in the mailroom.
Rather than hosting a public server itself, the receiver specifies a Payjoin Session associated with their Rather than hosting a public server itself, the receiver specifies a Payjoin Session associated with their
keypair's public key. This public key, compressed, hashed, truncated to 8 bytes, and bech32 encoded without a keypair's public key. This public key, compressed, hashed, truncated to 8 bytes, and bech32 encoded without a
checksum [[#short-id| short ID]], is used to identify a store-and-forward Session subdirectory on the Payjoin checksum [[#short-id| short ID]], is used to identify a store-and-forward mailbox on the
Directory server and establishes end-to-end encryption. As long as a Session is active, the receiver long mailroom server and establish end-to-end encryption. As long as a Session is active, the receiver long
polls GET requests to this subdirectory to await a payjoin request to a Payjoin Session from the sender. Out polls GET requests to this mailbox to await a message from the sender. Out
of band, the receiver shares a [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki| BIP 21]] of band, the receiver shares a [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki| BIP 21]]
Payjoin URI including the subdirectory endpoint in the <code>pj=</code> query parameter and a new Oblivious Payjoin URI including the mailbox endpoint in the <code>pj=</code> query parameter and a new Oblivious
HTTP <code>ohttp=</code> fragment parameter including the Payjoin Directory's [[https://www.ietf.org/rfc/ HTTP <code>ohttp=</code> fragment parameter including the Payjoin Mailroom's [[https://www.ietf.org/rfc/
rfc9458.html#name-key-configuration| OHTTP Key Configuration]]. rfc9458.html#name-key-configuration| OHTTP Key Configuration]].
The sender constructs an [[https://www.rfc-editor.org/rfc/rfc9180.html#name-authentication-using-an-asy| HPKE The sender constructs an [[https://www.rfc-editor.org/rfc/rfc9180.html#name-authentication-using-an-asy| HPKE
Auth mode]] payload containing a PSBT and optional parameters similar to BIP 78. The resulting ciphertext Auth mode]] payload containing a PSBT and optional parameters similar to BIP 78. The resulting ciphertext
ensures message secrecy and integrity when passed to the receiver using the subdirectory <code>pj=</code> ensures message secrecy and integrity when passed to the receiver using the mailbox <code>pj=</code>
endpoint. endpoint.
The receiver augments the Sender's PSBT with new inputs and outputs, and may adjust the fee. The receiver then The receiver augments the Sender's PSBT with new inputs and outputs, and may adjust the fee. The receiver then
encrypts the resulting PSBT and sends it back to the sender by POSTing it to a new subdirectory derived from encrypts the resulting PSBT and sends it back to the sender by POSTing it to a new mailbox derived from
the sender's reply key shared in their payload along with their original PSBT. the sender's reply key shared in their payload along with their original PSBT.
The sender will be long polling this second subdirectory for a response from the receiver. Upon receipt, the The sender will be long polling this second mailbox for a response from the receiver. Upon receipt, the
sender validates the receiver's Proposal PSBT, and if satisfied, signs its inputs and broadcasts the sender validates the receiver's Proposal PSBT, and if satisfied, signs its inputs and broadcasts the
transaction to the Bitcoin network. transaction to the Bitcoin network.
Messages are secured by symmetric cipher rather than TLS or Onion routing session key. Sender and receiver may Messages are secured by symmetric cipher rather than TLS or Onion routing session key. Sender and receiver may
experience network interruption and proceed with the protocol since their request and response are buffered at experience network interruption and proceed with the protocol since their request and response are buffered in the mailroom.
the Payjoin Directory.
====Sequence Diagram==== ====Sequence Diagram====
@@ -140,13 +139,12 @@ Key:
|-----> Single transmission |-----> Single transmission
|- - -> Polled transmission |- - -> Polled transmission
+----------+ +-----------+ +--------+ +---------+ +----------+ +----------+ +--------+ +---------+
| Receiver | | Directory | | Sender | | Network | | Receiver | | Mailroom | | Sender | | Network |
+----------+ +-----------+ +--------+ +---------+ +----------+ +----------+ +--------+ +---------+
| | | | | | | |
| | | | | | | |
| destination (address, | | | | destination (address, mailbox) | | |
| subdirectory) | | |
+---------------------------------------------------->| | +---------------------------------------------------->| |
| | | | | | | |
| GET Request Original PSBT | | | | GET Request Original PSBT | | |
@@ -179,26 +177,26 @@ The Payjoin version 2 protocol takes the following steps:
The <code>pj</code> URL path ends with the [[#short-id| short ID]], [[https://datatracker.ietf.org/doc/html/ The <code>pj</code> URL path ends with the [[#short-id| short ID]], [[https://datatracker.ietf.org/doc/html/
rfc4648#section-5| base64url-encoded]] followed by the [[#receiver-fragment-parameters| receiver fragment rfc4648#section-5| base64url-encoded]] followed by the [[#receiver-fragment-parameters| receiver fragment
parameters]]. parameters]].
* To support version 1 senders, the directory acts as an unsecured Payjoin server, so <code>pjos=0</code> * To support version 1 senders, the mailroom acts as an unsecured Payjoin server, so <code>pjos=0</code>
must be specified in the URI. Version 2 senders may safely allow output substitution regardless. must be specified in the URI. Version 2 senders may safely allow output substitution regardless.
* The sender creates a valid version 0 PSBT satisfying the [[https://github.com/bitcoin/bips/blob/master/bip- * The sender creates a valid version 0 PSBT satisfying the [[https://github.com/bitcoin/bips/blob/master/bip-
0078.mediawiki#receivers-original-psbt-checklist| the receiver checklist]]. We call this the <code>Original 0078.mediawiki#receivers-original-psbt-checklist| the receiver checklist]]. We call this the <code>Original
PSBT</code>. This <code>Original PSBT</code>, and optional sender parameters, are wrapped in HPKE authenticated PSBT</code>. This <code>Original PSBT</code>, and optional sender parameters, are wrapped in HPKE authenticated
encryption, including a sender session public key as associated data, and encapsulates it all as OHTTP. This encryption, including a sender session public key as associated data, and encapsulates it all as OHTTP. This
[[#send-messaging| Original PSBT Request send message]] is made to the directory's OHTTP Gateway. The request [[#send-messaging| Original PSBT Request send message]] is made to the mailroom's OHTTP Gateway. The request
is stored in the receiver subdirectory. is stored in the receiver mailbox.
* The sender polls GET requests to the subdirectory defined by the sender's Payjoin Session public key short * The sender polls GET requests to the mailbox defined by the sender's Payjoin Session public key short
ID in order to await a response from the directory containing a <code>Proposal PSBT</code>. It stops polling ID in order to await a response from the mailroom containing a <code>Proposal PSBT</code>. It stops polling
after expiry. after expiry.
* Once the receiver is online, it sends <code>GET</code> requests [[#receive-messaging| to the receiver * Once the receiver is online, it sends <code>GET</code> requests [[#receive-messaging| to the receiver
subdirectory]] requests to the subdirectory. The receiver decrypts and authenticates the response, which it mailbox]] requests to the mailbox. The receiver decrypts and authenticates the response, which it
checks according to [[https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-original-psbt- checks according to [[https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-original-psbt-
checklist| the receiver checklist]]. The receiver updates the Original PSBT to include new signed inputs and checklist| the receiver checklist]]. The receiver updates the Original PSBT to include new signed inputs and
outputs, invalidating sender signatures, and may adjust the fee. The result is called the <code>Proposal outputs, invalidating sender signatures, and may adjust the fee. The result is called the <code>Proposal
PSBT</code>. PSBT</code>.
* The <code>Proposal PSBT</code> and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and POSTed * The <code>Proposal PSBT</code> and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and POSTed
to the sender's subdirectory via the directory's OHTTP Gateway. to the sender's mailbox via the mailroom's OHTTP Gateway.
* The directory awaits a GET request from the sender. Upon request, the directory relays the encrypted * The mailroom awaits a GET request from the sender. Upon request, the mailroom relays the encrypted
<code>Proposal PSBT</code>. <code>Proposal PSBT</code>.
* The sender validates the <code>Proposal PSBT</code> according to [[#senders-proposal-psbt-checklist|the * The sender validates the <code>Proposal PSBT</code> according to [[#senders-proposal-psbt-checklist|the
sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network. sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network.
@@ -235,14 +233,14 @@ The Proposal PSBT MUST NOT:
Sessions between senders and receivers are established out of band when a receiver shares a Payjoin URI Sessions between senders and receivers are established out of band when a receiver shares a Payjoin URI
containing its Payjoin Session public key with a sender. containing its Payjoin Session public key with a sender.
A receiver must first discover the directory's OHTTP Gateway Key Configuration via an authenticated bootstrap A receiver must first discover the mailroom's OHTTP Gateway Key Configuration via an authenticated bootstrap
mechanism before it can initialize a Session to receive payjoin requests. This mechanism may vary by mechanism before it can initialize a Session to receive payjoin requests. This mechanism may vary by
implementation but must follow [[https://datatracker.ietf.org/doc/html/draft-ietf-privacypass-key-consistency- implementation but must follow [[https://datatracker.ietf.org/doc/html/draft-ietf-privacypass-key-consistency-
01| OHTTP Consistency Requirements]] and should not reveal a receiver IP address to the directory. Some 01| OHTTP Consistency Requirements]] and should not reveal a receiver IP address to the mailroom. Some
examples of suitable mechanisms include fetching over a VPN, using keys included with an application binary, examples of suitable mechanisms include fetching over a VPN, using keys included with an application binary,
https-in-http CONNECT method, https-in-WebSocket, or a Tor hidden service. https-in-http CONNECT method, https-in-WebSocket, or a Tor hidden service.
If a directory is subject to denial of service attacks, it may require [[https://datatracker.ietf.org/doc/html/ If a mailroom is subject to denial of service attacks, it may require [[https://datatracker.ietf.org/doc/html/
rfc6750| RFC 6750]] authorization and otherwise respond with <code>401</code> unauthorized responses to rfc6750| RFC 6750]] authorization and otherwise respond with <code>401</code> unauthorized responses to
requests. Authorization tokens must be unlinkable to preserve client privacy. A specific unlinkable requests. Authorization tokens must be unlinkable to preserve client privacy. A specific unlinkable
authorization token mechanism is out of the scope of this proposal. authorization token mechanism is out of the scope of this proposal.
@@ -251,25 +249,25 @@ authorization token mechanism is out of the scope of this proposal.
The Original PSBT is serialized in base64, followed by the query parameter string on a new line. This plaintext The Original PSBT is serialized in base64, followed by the query parameter string on a new line. This plaintext
string is encrypted according to HPKE using a shared secret derived from the sender's Payjoin Session public string is encrypted according to HPKE using a shared secret derived from the sender's Payjoin Session public
key combined with the receiver's subdirectory Payjoin Session public key. The resulting HPKE payload body is key combined with the receiver's mailbox Payjoin Session public key. The resulting HPKE payload body is
then encapsulated according to Oblivious HTTP as a POST request to the directory's OHTTP Gateway to the then encapsulated according to Oblivious HTTP as a POST request to the mailroom's OHTTP Gateway to the
receiver's payjoin session subdirectory. receiver's mailbox.
Upon receipt, the directory's OHTTP Gateway decapsulates the OHTTP request and handles the inner POST request Upon receipt, the mailroom's OHTTP Gateway decapsulates the OHTTP request and handles the inner POST request
at the receiver's Payjoin Session subdirectory endpoint, which stores the HPKE encrypted payload to be at the receiver's Payjoin Session mailbox endpoint, which stores the HPKE encrypted payload to be
forwarded to the receiver. forwarded to the receiver.
The sender then polls GET requests to the sender's Payjoin Session subdirectory endpoint in order to await a The sender then polls GET requests to the sender's Payjoin Session mailbox endpoint in order to await a
response from the directory containing a <code>Proposal PSBT</code>. It stops polling after expiry. response from the mailroom containing a <code>Proposal PSBT</code>. It stops polling after expiry.
====Receive Messaging==== ====Receive Messaging====
After sharing the Payjoin URI with the sender, the receiver sends a GET request to the path of the receiver's After sharing the Payjoin URI with the sender, the receiver sends a GET request to the path of the receiver's
Payjoin Session subdirectory. This request is encapsulated in OHTTP. It continues to poll by sending a new Payjoin Session mailbox. This request is encapsulated in OHTTP. It continues to poll by sending a new
OHTTP request after receiving an encapsulated 202 ACCEPTED response notifying the receiver that the directory OHTTP request after receiving an encapsulated 202 ACCEPTED response notifying the receiver that the mailroom
has not yet received a request from the sender. has not yet received a request from the sender.
Upon receiving OHTTP response from the directory encapsulating a request from the sender with status code 200 Upon receiving OHTTP response from the mailroom encapsulating a request from the sender with status code 200
OK, the receiver decrypts the payload and checks the <code>Proposal PSBT</code> according to the [[#receivers- OK, the receiver decrypts the payload and checks the <code>Proposal PSBT</code> according to the [[#receivers-
proposal-psbt-checklist|checklist]]. proposal-psbt-checklist|checklist]].
@@ -281,8 +279,8 @@ keypair from which it derives a shared secret with the sender's Payjoin Session
It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Proposal PSBT and It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Proposal PSBT and
serialized receiver ephemeral key <code>e</code>'s public key as associated data using ChaCha20Poly1305. A serialized receiver ephemeral key <code>e</code>'s public key as associated data using ChaCha20Poly1305. A
payload is constructed by concatenating the ephemeral public key, the nonce, and the ciphertext. This Proposal payload is constructed by concatenating the ephemeral public key, the nonce, and the ciphertext. This Proposal
PSBT payload is then sent as a POST message to the directory in an OHTTP request encapsulating the binary PSBT payload is then sent as a POST message to the mailroom in an OHTTP request encapsulating the binary
payload to the sender's Payjoin Session subdirectory. payload to the sender's Payjoin Session mailbox.
===Receiver's Original PSBT checklist=== ===Receiver's Original PSBT checklist===
@@ -298,24 +296,24 @@ script types are allowed, and it expects all UTXO data to be filled in. BIP 78 r
to be excluded from the PSBT, which has caused many issues, as it required the sender to add them back to the to be excluded from the PSBT, which has caused many issues, as it required the sender to add them back to the
Payjoin proposal PSBT. Version 2 has no such requirement. Payjoin proposal PSBT. Version 2 has no such requirement.
===Directory interactions=== ===Mailroom interactions===
The Payjoin Directory provides a rendezvous point for sender and receiver to meet. The directory stores Payjoin The Payjoin Mailroom provides a rendezvous point for sender and receiver to meet. The mailroom stores Payjoin
payloads to support asynchronous communication. The directory must only accept OHTTP requests with an OHTTP payloads to support asynchronous communication. The mailroom must only accept OHTTP requests with an OHTTP
Gateway for Payjoin version 2, accepting encrypted payloads. The directory may optionally accept HTTP/1.1 POST Gateway for Payjoin version 2, accepting encrypted payloads. The mailroom may optionally accept HTTP/1.1 POST
requests without OHTTP to Payjoin Session subdirectories for backwards compatibility with Payjoin version 1 requests. requests without OHTTP to mailbox URLs for backwards compatibility with Payjoin version 1 requests.
===Subdirectories=== ===Mailboxes===
Each Payjoin Session subdirectory allocated on the directory has one buffer for a PSBT payload. The buffer Each Payjoin Session mailbox allocated in the mailroom has one buffer for a PSBT payload. The buffer
updates listeners through awaitable events so that updates are immediately apparent upon client request. updates listeners through awaitable events so that updates are immediately apparent upon client request.
====Short ID==== ====Short ID====
Short IDs are an 8-byte identifier for a Payjoin Session subdirectory. They are generated by hashing a Short IDs are an 8-byte identifier for a Payjoin Session mailbox. They are generated by hashing a
compressed secp256k1 public key with Sha256, truncating it to 8 bytes, and encoding it in bech32 with the HRP compressed secp256k1 public key with Sha256, truncating it to 8 bytes, and encoding it in bech32 with the HRP
"ID". The Short ID HRP prefix (including the '1' separator) "ID1" is stripped from the bech32 encoded uppercase "ID". The Short ID HRP prefix (including the '1' separator) "ID1" is stripped from the bech32 encoded uppercase
string before it is used as the subdirectory identifier. string before it is used as the mailbox identifier.
64 bits are sufficient to make the probability of experiencing a random collisions negligible. As of writing, 64 bits are sufficient to make the probability of experiencing a random collisions 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) the UTXO set has ~2^28 elements. This is a very loose upper bound for the number of concurrent (non-spam)
@@ -334,9 +332,9 @@ Instead of defining new [[https://github.com/bitcoin/bips/blob/master/bip-0021.m
parameters, Payjoin version 2 encodes parameters in the [[https://datatracker.ietf.org/doc/html/rfc3986#section- parameters, Payjoin version 2 encodes parameters in the [[https://datatracker.ietf.org/doc/html/rfc3986#section-
3.5| fragment]] of the URL following the <code>pj=</code> parameter in the BIP 21 URI. They follow the 3.5| fragment]] of the URL following the <code>pj=</code> parameter in the BIP 21 URI. They follow the
<code>#</code> as bech32 parameters separated by a <code>+</code> character. In order to simplify parsing and <code>#</code> as bech32 parameters separated by a <code>+</code> character. In order to simplify parsing and
allow QR encoders to use alphanumeric QR mode wherever possible, the <code>pj</code> parameter subdirectory and allow QR encoders to use alphanumeric QR mode wherever possible, the <code>pj</code> parameter mailbox and
fragment that follows must be uppercased and should come as the last parameter of the URI. Since URLs are case fragment that follows must be uppercased and should come as the last parameter of the URI. Since URLs are case
sensitive, path elements of a payjoin-directory may be lowercased but SHOULD be configured to be uppercased. sensitive, path elements of a mailroom URL may be lowercased but SHOULD be configured to be uppercased.
The '#' fragment separator character must be [[https://datatracker.ietf.org/doc/html/rfc3986| RFC 3986]] The '#' fragment separator character must be [[https://datatracker.ietf.org/doc/html/rfc3986| RFC 3986]]
percent-encoded as '%23' according to BIP 21. percent-encoded as '%23' according to BIP 21.
@@ -346,8 +344,8 @@ according to their role:
* <code>RK</code>: represents the receiver's Payjoin Session public key. This is a compressed public key of the * <code>RK</code>: represents the receiver's Payjoin Session public key. This is a compressed public key of the
receiver's Payjoin Session. Senders will initiate HPKE with the receiver using this key. receiver's Payjoin Session. Senders will initiate HPKE with the receiver using this key.
* <code>OH</code>: represents the OHTTP Key Configuration of the directory. This is a compressed public key of * <code>OH</code>: represents the OHTTP Key Configuration of the mailroom. This is a compressed public key of
the directory's OHTTP Gateway, prefixed by the 2-byte Key Identifier, from which the [[https://www.ietf.org/rfc/ the mailroom's OHTTP Gateway, prefixed by the 2-byte Key Identifier, from which the [[https://www.ietf.org/rfc/
rfc9458.html#section-3.1| RFC 9458 Key Configuration can be constructed]]. This parameter is required for Payjoin rfc9458.html#section-3.1| RFC 9458 Key Configuration can be constructed]]. This parameter is required for Payjoin
version 2 URIs. version 2 URIs.
* <code>EX</code>: represents a request expiration in [[https://pubs.opengroup.org/onlinepubs/9699919799/ * <code>EX</code>: represents a request expiration in [[https://pubs.opengroup.org/onlinepubs/9699919799/
@@ -376,7 +374,7 @@ BIP 78's optional query parameters are also valid as version 2 parameters.
===Request expiration & Original PSBT=== ===Request expiration & Original PSBT===
The directory may hold a request for an offline payjoin peer until that peer comes online. However, the BIP 78 The mailroom may hold a request for an offline payjoin peer until that peer comes online. However, the BIP 78
spec [[https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receiver-does-not-need-to-be-a-full-node| spec [[https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receiver-does-not-need-to-be-a-full-node|
recommends]] broadcasting Original PSBTs in the case of an offline counterparty. Doing so exposes a naïve, recommends]] broadcasting Original PSBTs in the case of an offline counterparty. Doing so exposes a naïve,
surveillance-vulnerable transaction which Payjoin intends to avoid. surveillance-vulnerable transaction which Payjoin intends to avoid.
@@ -394,8 +392,8 @@ WebSockets protocol, plain HTTP can benefit from metadata protection by using Ob
===Oblivious HTTP=== ===Oblivious HTTP===
OHTTP protects sender and receiver IP addresses both from one another and from the directory. This makes it OHTTP protects sender and receiver IP addresses both from one another and from the mailroom. This makes it
more difficult for a directory to correlate many payjoin transactions with specific IP addresses by more difficult for a mailroom to correlate many payjoin transactions with specific IP addresses by
intersection. intersection.
OHTTP relays can be run as basic HTTP proxies from wallet providers or third parties. OHTTP relays can be run as basic HTTP proxies from wallet providers or third parties.
@@ -406,7 +404,7 @@ OHTTP relays can be run as basic HTTP proxies from wallet providers or third par
===Uniform Payloads=== ===Uniform Payloads===
Encapsulated OHTTP payloads and messages seen by the Payjoin Directory are constructed to be uniform so that Encapsulated OHTTP payloads and messages seen by the mailroom are constructed to be uniform so that
the third-party services are unable to distinguish between them based on payload size or by distinguishing the third-party services are unable to distinguish between them based on payload size or by distinguishing
them from random bytes. However, the Encapsulated OHTTP message includes an uncompressed key for the DHKEM them from random bytes. However, the Encapsulated OHTTP message includes an uncompressed key for the DHKEM
which is distinguishable from random bytes but uniform across different encapsulated requests. which is distinguishable from random bytes but uniform across different encapsulated requests.
@@ -414,13 +412,13 @@ which is distinguishable from random bytes but uniform across different encapsul
OHTTP messages are padded to 8192 bytes. OHTTP messages are padded to 8192 bytes.
HPKE message payloads are padded to 7168 bytes. Elligator swift is used to encode encapsulated HPKE public keys HPKE message payloads are padded to 7168 bytes. Elligator swift is used to encode encapsulated HPKE public keys
prepended to the HPKE ciphertext so that the payjoin directory can't distinguish between key material, the prepended to the HPKE ciphertext so that the mailroom can't distinguish between key material, the
ciphertext, and randomness, so that the directory may accommodate new protocols in the future without ciphertext, and randomness, so that the mailroom may accommodate new protocols in the future without
discrimination. discrimination.
This is sufficient size for most PSBTs without exceeding the [[https://www.geekersdigest.com/max-http-request- This is sufficient size for most PSBTs without exceeding the [[https://www.geekersdigest.com/max-http-request-
header-size-server-comparison/| 8KB limit]] of many HTTP/1.1 web servers. 8KB is also too small for image header-size-server-comparison/| 8KB limit]] of many HTTP/1.1 web servers. 8KB is also too small for image
sharing, making misuse of the Payjoin Directory impractical. sharing, making misuse of the mailroom impractical.
====Message Byte Representations==== ====Message Byte Representations====
@@ -472,7 +470,7 @@ noiseprotocol.org/noise.html#zero-rtt-and-noise-protocols| zero-RTT]] version of
org/noise.html| Noise Framework]] [[https://noiseexplorer.com/patterns/IK/| IK]] pattern. A receiver shares its org/noise.html| Noise Framework]] [[https://noiseexplorer.com/patterns/IK/| IK]] pattern. A receiver shares its
public key out of band in the BIP 21 URI. Static keys shared in URIs must only be used for a single Payjoin public key out of band in the BIP 21 URI. Static keys shared in URIs must only be used for a single Payjoin
Session. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5| base64url]] encoding Session. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5| base64url]] encoding
as a Payjoin Directory subdirectory in the <code>pj=</code> parameter. as a mailbox URL fragment in the <code>pj=</code> parameter.
====Secp256k1-based DHKEM==== ====Secp256k1-based DHKEM====
@@ -497,9 +495,9 @@ SHA-256 is considered secure and is necessarily available in bitcoin contexts.
In addition to the attack vectors and mitigations in [[https://github.com/bitcoin/bips/blob/master/bip-0078. In addition to the attack vectors and mitigations in [[https://github.com/bitcoin/bips/blob/master/bip-0078.
mediawiki#attack-vectors| BIP 78 Payjoin version 1]], Payjoin version 2 has the following attack vectors. mediawiki#attack-vectors| BIP 78 Payjoin version 1]], Payjoin version 2 has the following attack vectors.
Since directories store arbitrary encrypted payloads they are vulnerable to the tragedy of the commons and Since each mailbox stores arbitrary encrypted payloads they are vulnerable to the tragedy of the commons and
denial of service attacks. To mitigate such attacks, directory operators may impose an authentication denial of service attacks. To mitigate such attacks, mailroom operators may impose an authentication
requirement before they allocate a Payjoin Session subdirectory to receivers. requirement before they allocate a Payjoin Session mailbox to receivers.
Since we make use of 0-RTT HPKE, the first message containing the sender's Original PSBT has minimal forward Since we make use of 0-RTT HPKE, the first message containing the sender's Original PSBT has minimal forward
secrecy. If the receiver's key is compromised, this message containing the Original PSBT could be read by the secrecy. If the receiver's key is compromised, this message containing the Original PSBT could be read by the
@@ -513,14 +511,14 @@ norm, so falling back to them is no worse than typical bitcoin transaction behav
===Network privacy=== ===Network privacy===
Oblivious HTTP must be used to protect the IP addresses of both sender and receiver from the directory. This Oblivious HTTP must be used to protect the IP addresses of both sender and receiver from the mailroom. This
requires an OHTTP Key Configuration to be shared in the BIP 21 URI and for the directory to support Oblivious requires an OHTTP Key Configuration to be shared in the BIP 21 URI and for the mailroom to support Oblivious
HTTP. A secp256k1 HPKE OHTTP configuration should be used to leverage the cryptography already available in HTTP. A secp256k1 HPKE OHTTP configuration should be used to leverage the cryptography already available in
bitcoin contexts. bitcoin contexts.
Unlike BIP 78 implementations, sender and receiver peers will only see the IP address of the directory and not Unlike BIP 78 implementations, sender and receiver peers will only see the IP address of the mailroom and not
that of their peers. Directories may additionally be made available via Tor hidden services to allow either of that of their peers. A mailroom may additionally be made available via Tor hidden service to allow either of
the peers to protect their IP from the directory without OHTTP. the peers to protect their IP from the mailroom without OHTTP.
==Backwards compatibility== ==Backwards compatibility==
@@ -535,16 +533,16 @@ MUST consider the entire URI invalid per BIP 21.
Receivers may choose to support version 1 payloads. Payjoin version 2 URIs for backwards compatible receivers Receivers may choose to support version 1 payloads. Payjoin version 2 URIs for backwards compatible receivers
MUST enable <code>pjos=0</code> so that these version 1 senders disable output substitution. Since the version MUST enable <code>pjos=0</code> so that these version 1 senders disable output substitution. Since the version
1 messages are neither encrypted nor authenticated, they would otherwise be at risk for man-in-the-middle 1 messages are neither encrypted nor authenticated, they would otherwise be at risk for man-in-the-middle
attacks. The directory protocol should carry on as normal, responding to payjoin requests instead with this attacks. The mailroom protocol should carry on as normal, responding to payjoin requests instead with this
version 1 request as [[https://www.rfc-editor.org/v3test/htmlredo/rfc9292.html| BHTTP]] in an OHTTP response. The receiver should POST Payjoin version 1 Proposal PSBTs to the same version 1 request as [[https://www.rfc-editor.org/v3test/htmlredo/rfc9292.html| BHTTP]] in an OHTTP response. The receiver should POST Payjoin version 1 Proposal PSBTs to the same
subdirectory as in version 2 to respond to these version 1 senders within 30 seconds. If no response is mailbox as in version 2 to respond to these version 1 senders within 30 seconds. If no response is
received within 30 seconds, the directory should respond with an <code>unavailable</code> error code as received within 30 seconds, the mailroom should respond with an <code>unavailable</code> error code as
[[https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-well-known-errors| defined in BIP [[https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-well-known-errors| defined in BIP
78]]. 78]].
==Reference implementation== ==Reference implementation==
An production reference implementation client can be found at [[https://crates.io/crates/payjoin-cli]]. Source An production reference implementation client can be found at [[https://crates.io/crates/payjoin-cli]]. Source
code for the clients, the Payjoin Directory, and development kit may be found here: [[https://github.com/payjoin/ code for the clients, the mailroom, 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/ rust-payjoin]]. Source code for an Oblivious HTTP relay implementation may be found here [[https://github.com/
payjoin/ohttp-relay]]. payjoin/ohttp-relay]].