diff --git a/README.mediawiki b/README.mediawiki index 94ecb8bcb..34a83ac8c 100644 --- a/README.mediawiki +++ b/README.mediawiki @@ -400,6 +400,13 @@ Those proposing changes should consider that ultimately consent may rest with th | Standard | Final |- +| [[bip-0077.mediawiki|77]] +| Applications +| Payjoin Version 2 — Async Payjoin +| Dan Gould +| Standard +| Draft +|- | [[bip-0078.mediawiki|78]] | Applications | A Simple Payjoin Proposal diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki new file mode 100644 index 000000000..e82f110f9 --- /dev/null +++ b/bip-0077.mediawiki @@ -0,0 +1,280 @@ +
+  BIP: 77
+  Layer: Applications
+  Title: Payjoin Version 2 — Async Payjoin
+  Author: Dan Gould 
+  Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0077
+  Status: Draft
+  Type: Standards Track
+  Created: 2023-08-08
+  License: BSD-2-Clause
+
+ +==Abstract== + +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 substitution, without requiring one 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 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 the directory and Payjoin peers from linking requests to client IP addresses. + +==Copyright== + +This BIP is licensed under the 2-clause BSD license. + +==Motivation== + +Payjoin is the simplest case of interactive bitcoin batching, allowing two participants to combine their transaction intents. It solves the sole privacy problem left open in the bitcoin paper, that transactions with multiple inputs "necessarily reveal that their inputs were owned by the same owner," by enabling two owners to provide input in a transaction. + +The Payjoin protocols automate cooperative transaction construction to break that common-input assumption. The increased opportunity to batch payments and execute transaction cut-through increases intent throughput, since multiple intents combined take up fewer bytes than independent transactions. + +Payjoin version 1's requirements have proven to be an obstacle to adoption. Version 1 coordinates payjoins over a public server endpoint secured by either TLS or Tor hidden service hosted by the receiver. Version 1 is also synchronous, requiring both sender and receiver to be online simultaneously to payjoin. Both requirements present significant barriers for all but sophisticated server operators or those wallets with complex Tor integration. Wallet developers [[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-January/018358.html| regard]] these as limits to Payjoin adoption. + +The primary goal of this proposal is to provide a practical coordination mechanism that can be implemented in a majority of bitcoin software environments. This is done here using a simple protocol built on bitcoin URI requests, web standards, common cryptography, and minimal dependencies. + +===Relation to BIP 78 (Payjoin version 1)=== + +The message payloads in this version parallel those used in BIP 78, while being encapsulated in authenticated encryption. TLS and Tor security, which depend on third-party authorities, are replaced with Hybrid Public Key Encryption ([[https://www.rfc-editor.org/rfc/rfc9180| HPKE]]). The synchronous HTTP client-server model is replaced with an asynchronous store-and-forward mechanism. + +The BIP 78 standard allows for an [[https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#unsecured-payjoin-server| unsecured Payjoin server|]] to operate separately from the so-called "payment server" responsible for generating [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki| BIP 21]] request URIs. Because BIP 78 messages relayed over an unsecured server are neither end-to-end authenticated nor 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 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 compromising sender or receiver privacy. + +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 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 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 introduced which may also help coordinate the synchronous version 1 protocol. + +===Relation to Stowaway=== + +[[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/blob/master/bip-0047.mediawiki| BIP 47]] "payment codes" directory for subdirectory identification and encryption. The Payjoin version 2 protocol uses per-request public keys for relay subdirectory identification, 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 manual message passing rather than an asynchronous network protocol. Successful Stowaway execution results in 2-output transactions, while BIP 78, and this work may produce batched transactions with many outputs. + +==Specification== + +===Overview=== + +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 Payjoin messages. Directories 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 asynchronous interaction. Authenticated encryption prevents the directory from snooping on message contents 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 encryption and relayed asynchronous networking, version 2 messaging takes much the same form as the existing BIP 78 specification. + +===Basic scheme=== + +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. + +Rather than hosting a public server itself, the receiver initializes a Payjoin Session by requesting a subdirectory allocation related to their keypair's public key. This public key is used to identify a store-and-forward Session subdirectory on the Payjoin Directory server and establishes end-to-end encryption. A POST request to the Payjoin Directory including the receiver's public key initiates an associated Payjoin Session. A successful 201 CREATED response message from the directory to the receiver includes the new Session subdirectory payjoin endpoint in the Location header using the compressed public key as a subdirectory identifier. As long as a Session is active, the receiver uses long polling to await a payjoin request to a Payjoin Session from the sender. Out of band, the receiver shares a [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki| BIP 21]] Payjoin URI including the directory endpoint in the pj= query parameter and a new Oblivious HTTP ohttp= fragment parameter including the Payjoin Directory's [[https://www.ietf.org/rfc/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 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 by the subdirectory pj= endpoint. + +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 the Payjoin Directory. + +====Sequence Diagram==== + +
+Key: 
+|-----> Single transmission
+|- - -> Polled transmission
+
++----------+                 +-----------+       +--------+  +---------+
+| Receiver |                 | Directory |       | Sender |  | Network |
++----------+                 +-----------+       +--------+  +---------+
+|                                  |                  |                |
+|                                  |                  |                |
+|      destination (address,       |                  |                |
+|        subdirectory)             |                  |                |
++---------------------------------------------------->|                |
+|                                  |                  |                |
+|    GET Request Original PSBT     |                  |                |
++- - - - - - - - - - - - - - - - ->|   POST Request   |                |
+|                                  |  Original PSBT   |                |
+|    GET Response Original PSBT    |<-----------------|                |
+|<---------------------------------|   GET Request    |                |
+|                                  |  Proposal PSBT   |                |
+|                                  |<- - - - - - - - -|                |
+|                                  |                  |                |
+|                                  |                  |                |
+|                                  |                  |                |
+|      POST Proposal PSBT          |                  |                |
++--------------------------------->|   GET Response   |                |
+|                                  |   Proposal PSBT  |                |
+|                                  |----------------->|                |
+|                                  |                  |   Broadcast    |
+|                                  |                  |   Payjoin      |
+|                                  |                  +--------------->|
+|                                  |                  |                |
++                                  +                  +                +
+
+ +===Payjoin version 2 messaging=== + +The Payjoin version 2 protocol takes the following steps: + +* The receiver generates a Payjoin Session public key. +* Out of band, the receiver shares a bitcoin URI with the sender, including a pj= query parameter. The pj URL contains the compressed Payjoin Session public key, [[https://datatracker.ietf.org/doc/html/rfc4648#section-5| base64url-encoded]] followed by the [[#receiver-fragment-parameters| receiver fragment parameters]] . + * To support version 1 senders, the directory acts as an unsecured Payjoin server, so pjos=0 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-0078.mediawiki#receivers-original-psbt-checklist| the receiver checklist]]. We call this the Original PSBT. This Original PSBT, 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 [[#send-messaging| Original PSBT Request send message]] is made to the directory's OHTTP Gateway. The request is stored in the receiver subdirectory. +* The sender polls GET requests to the subdirectory defined by the sender's Payjoin Session public key in order to await a response from the directory containing a Proposal PSBT. It stops polling after expiry. +* Once the receiver is online, it sends GET requests [[#receive-messaging| to the receiver subdirectory]] requests to the subdirectory. 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-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 Proposal PSBT. +* The Proposal PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and POSTed to the directory's OHTTP Gateway. +* The directory awaits a GET request from the sender. Upon request, the directory relays the encrypted Proposal PSBT. +* The sender validates the Proposal PSBT according to [[#senders-proposal-psbt-checklist|the sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network. + +The Original PSBT MUST: + +* Include complete UTXO data. +* Be 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. + +The Proposal PSBT MUST: + +* Include all inputs from the Original PSBT. +* Include all outputs which do not belong to the receiver from the Original PSBT. +* Include complete UTXO data. + +The Proposal PSBT sender MAY: + +* Add, 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; the additional outputs or additional inputs must be inserted at a random index. +* Decrease the absolute fee of the Original PSBT. + +====Session Initiation==== + +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. + +A receiver must first discover the directory'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 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 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. + +Senders and receivers POST their Payjoin Session public key to the directory via OHTTP, receiving their subdirectory in a base64url encoded directory URL in the Location header of a 201 CREATED response. + +If a directory is subject to denial of service attacks, it may require [[https://datatracker.ietf.org/doc/html/rfc6750| RFC 6750]] authorization and otherwise respond with 401 unauthorized responses to requests. Authorization tokens must be unlinkable to preserve client privacy. A specific unlinkable authorization token mechanism is out of the scope of this proposal. + +====Send Messaging==== + +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 key combined with the receiver's subdirectory 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 receiver's payjoin session subdirectory. + +Upon receipt, the directory'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 forwarded to the receiver. + +The sender then polls GET requests to the sender's Payjoin Session subdirectory endpoint in order to await a response from the directory containing a Proposal PSBT. It stops polling after expiry. + +====Receive Messaging==== + +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 OHTTP request after receiving an encapsulated 202 ACCEPTED response notifying the receiver that the directory 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 OK, the receiver decrypts the payload and checks the Proposal PSBT according to the [[#receivers-proposal-psbt-checklist|checklist]]. + +The receiver then updates the Original PSBT to include new signed inputs and outputs, invalidating sender signatures, and may adjust the fee. The result is called the Proposal PSBT. + +The receiver encrypts the Proposal PSBT according to the HPKE protocol, generating an ephemeral keypair from which it derives a shared secret with the sender's Payjoin Session public key from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Proposal PSBT and serialized receiver ephemeral key e'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 PSBT payload is then sent as a POST message to the directory in an OHTTP request encapsulating the binary payload to the sender's Payjoin Session subdirectory. + +===Receiver's Proposal PSBT checklist=== + +The receiver checklist is the same as the [[https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-original-psbt-checklist| the BIP 78 receiver checklist]], except for the "Verify that the payjoin proposal did not introduce mixed input's type" step, which may be ignored. + +===Sender's Proposal PSBT checklist=== + +The version 2 sender's checklist is largely the same as the [[https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#senders-payjoin-proposal-checklist| the BIP 78 checklist]], with the exception that mixed input script types are allowed, and it expects all UTXO data to be filled in. BIP 78 required sender inputs UTXO data 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. + +===Directory interactions=== + +The Payjoin Directory provides a rendezvous point for sender and receiver to meet. The directory stores Payjoin payloads to support asynchronous communication. The directory 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 requests without OHTTP to Payjoin Session subdirectories to support backwards compatible Payjoin version 1 requests. + +===Subdirectories=== + +Each Payjoin Session subdirectory allocated on the directory has one buffer for a PSBT payload. The buffer updates listeners through awaitable events so that updates are immediately apparent upon client request. + +===Receiver fragment parameters=== + +A major benefit of BIP 78 Payjoin over other coordination mechanisms is its compatibility with the universal BIP 21 bitcoin URI standard. + +Instead of defining new [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki| BIP 21 URI]] parameters, Payjoin version 2 encodes parameters in the [[https://datatracker.ietf.org/doc/html/rfc3986#section-3.5| fragment]] of the URL following the pj= parameter in the BIP 21 URI. They follow the # character and follow the semantics of the [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki#abnf-grammar| BIP 21 "otherparam" grammar]], being separated by an & character. + +* ohttp: represents the OHTTP Key Configuration of the directory. This is a base64url encoded compressed public key of the directory's OHTTP Gateway, prefixed by the one 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 version 2 Payjoin URIs. +* exp: represents a request expiration in [[https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16| Unix time]] after which the receiver reserves the right to broadcast the transaction extracted from the Original PSBT and ignore requests. This is only necessary for receivers who only support synchonous execution of the protocol, like automated payment processors. + +The '=' and '&' characters parameters must be [[https://datatracker.ietf.org/doc/html/rfc3986| RFC 3986]] percent-encoded as '%3D' and '%26' respectively according to BIP 21. + +For example, a properly encoded endpoint URL fragment looks like this bitcoin:bcrt1qq34p97ah7fwxl3mnuyvtlg2serkawma8r9ylzr?pj=https://payjo.in/AoE6sWvRXaG5VAxea61t39syjhQGELKcXiI0DiLlnKtE#ohttp%3DAQJEXdFvFV4dCy48eYt8NEDsAXQznb67o2HObVYuE50cHg%26exp%3D1727464869&pjos=0 + +Using the fragment for Payjoin URI parameters makes for more compact QR codes too, since all of the characters are contained in alphanumeric QR mode is more compact than the byte mode. + +===Optional sender parameters=== + +When a Payjoin sender POSTs an Original PSBT to the receiver, the sender should specify the following HTTP query string parameters: + +* v: represents the version number of the Payjoin protocol that the sender is using. This version is 2. + +BIP 78's optional query parameters are also valid as version 2 parameters. + +==Rationale== + +===Request expiration & Original PSBT=== + +The directory 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| 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. + +The existing BIP 78 protocol has to be synchronous only for automated endpoints, which may be vulnerable to probing attacks. It can cover this tradeoff by demanding an Original PSBT, from which a valid payment transaction may be extracted that would not preserve privacy the same way as a payjoin. BIP 21 URIs can communicate a request expiration to alleviate both of these problems. Receivers may specify a deadline after which they will broadcast this original with a new expiration parameter exp=. + +===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 by intersection. + +OHTTP relays can be run as basic HTTP proxies from wallet providers or third parties. + +====OHTTP Sequence Diagram==== + + + + +===Message Padding=== + +All ciphertexts should be padded to the same length of 7168 bytes to prevent traffic analysis. 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 sharing, making misuse of the Payjoin Directory impractical. + +===Secp256k1 Hybrid Public Key Encryption=== + +Hybrid Public Key Encryption (HPKE) is a modern web standard for secure message exchange without TLS. Since client and server agree on a configuration out of band, we can pre-define the Payjoin version 2 application specific configuration to use DHKEM(Secp256k1, HKDF-SHA256) and ChaCha20Poly1305 AEAD. + +The cryptographic handshake is conducted in parallel to the payjoin messaging inspired by the [[http://www.noiseprotocol.org/noise.html#zero-rtt-and-noise-protocols| zero-RTT]] version of the [[http://www.noiseprotocol.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 Session. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5| base64url]] encoding as a Payjoin Directory subdirectory in the pj= parameter. + +====Secp256k1-based DHKEM==== + +[[https://www.ietf.org/archive/id/draft-wahby-cfrg-hpke-kem-secp256k1-01.html| Secp256k1-based DHKEM for HPKE]] is most appropriate because of secp256k1's availability in bitcoin contexts. + +====ChaCha20Poly1305 AEAD==== + +This authenticated encryption with additional data [[https://en.wikipedia.org/wiki/ChaCha20-Poly1305| algorithm]] is standardized in [[https://www.rfc-editor.org/rfc/rfc8439| RFC 8439]] and has high performance. ChaCha20Poly1305 AEAD has been implemented [[https://github.com/bitcoin/bitcoin/pull/15649| in Bitcoin Core]] [[https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki| BIP 324]] as well. The protocol has widespread support in browsers, OpenSSL and libsodium. AES-GCM is more widespread but is both older, slower, and not necessarily already a dependency in bitcoin software. + +====HKDF-SHA256==== + +SHA-256 is considered secure and is necessarily available in bitcoin contexts. + +===Attack vectors=== + +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. + +Since directories store 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 requirement before they allocate a Payjoin Session subdirectory to receivers. + +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 compromiser. + +Receivers may break spec by ignoring the exp= without financial consequence since the sender payload contains a valid transaction that may be broadcast at any time. There is no mechanism to enforce penalties if a receiver fails to construct a Proposal PSBT and wait for a signature once a Proposal PSBT is returned to a sender. However, such basic transactions that comply with the common-input assumption are the norm, so falling back to them is no worse than typical bitcoin transaction behavior. + +===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 BIP 21 URI and for the directory to support Oblivious HTTP. A secp256k1 HPKE OHTTP configuration should be used to leverage the cryptography already available in bitcoin contexts. + +Unlike BIP 78 implementations, sender and receiver peers will only see the IP address of the directory and not that of their peers. Directories may additionally be made available via Tor hidden services to allow either of the peers to protect their IP from the directory without OHTTP. + +==Backwards compatibility== + +The receivers advertise Payjoin capabilities through [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki| BIP 21's URI Scheme]]. + +Senders not supporting Payjoin will just ignore the pj= parameter and proceed to typical address-based transaction flows. A req-pj= parameter, as specified in BIP 21, may be advertised to compel Payjoin. If a sender intending to pay such a URI containing req-pj= does not support Payjoin, it MUST consider the entire URI invalid per BIP 21. + +Receivers may choose to support version 1 payloads. Version 2 Payjoin URIs for backwards compatible receivers MUST enable pjos=0 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 attacks. The directory protocol should carry on as normal, responding to payjoin requests instead with this version 1 request as BHTTP in an OHTTP response. The receiver should POST 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 received within 30 seconds, the directory should respond with an unavailable error code as [[https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-well-known-errors| defined in BIP 78]]. + +==Reference implementation== + +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/rust-payjoin]]. Source code for an Oblivous HTTP relay implementation may be found here [[https://github.com/payjoin/ohttp-relay]]. The reference implementation may be configured to the following independent production relays as of 24/09/26: + +A Payjoin Directory is run by the Payjoin Dev Kit team on [[https://payjo.in]]. + +An independent Oblivious HTTP relay is run by [[https://www.bobspaces.net| BOB Spaces]] at [[https://pj.bobspacebkk.com]]. diff --git a/bip-0077/oblivious-http-sequence.png b/bip-0077/oblivious-http-sequence.png new file mode 100644 index 000000000..62e293431 Binary files /dev/null and b/bip-0077/oblivious-http-sequence.png differ