From 5e2f2aad1c2e3a2c11195dfe254b4a9eb0d9423e Mon Sep 17 00:00:00 2001 From: DanGould Date: Sat, 3 Jun 2023 18:50:33 -0400 Subject: [PATCH 01/50] Draft payjoin v2 BIP --- bip-???-payjoin-v2.mediawiki | 142 +++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 bip-???-payjoin-v2.mediawiki diff --git a/bip-???-payjoin-v2.mediawiki b/bip-???-payjoin-v2.mediawiki new file mode 100644 index 0000000000..0e3b33e4ba --- /dev/null +++ b/bip-???-payjoin-v2.mediawiki @@ -0,0 +1,142 @@ +
+  BIP: ???
+  Title: Serverless Payjoin
+  Author: Dan Gould 
+  Replaces: 78
+  Status: Draft
+  Type: Standards Track
+  Created: 2023-04-08
+  License: BSD-2-Clause
+
+ +==Abstract== + +This document proposes a second version of the payjoin protocol described in BIP 78, allowing full payjoin receiver functionality including payment output substitution without the requirement to host a secure public endpoint. This requirement is replace with network protocols available in all modern web browsers. + +===Copyright=== + +This BIP is licensed under the 2-clause BSD license. + +==Motivation== + +Payjoin[^1] 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."[^2] Breaking that common-input ownership assumption requires contributions from multiple owners via interaction, namely hosting a server endpoint secured by a certificate on the receiving side either via TLS or Tor onion hidden service. Because the protocol is synchronous, both sender and reciever must be online to payjoin. These problems of convenience have been identified as the greatest barriers to widespread payjoin adoption.[^3] + +===Relation to BIP 78 (Payjoin v1)=== + +The BIP 78 standard allows for an [[#|unsecured payjoin server|]] to operate separately from the so-called "payment server" which generates [[bip-0021.mediawiki|BIP 21]] request URIs. Because BIP 78 messages are neither authenticated nor encrypted a malicious unsecured payjoin server is able to modify the Payjoin PSBT in flight, thus requiring [[payment output substitition]] to be disabled. Output substitition 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 substition without compromising sender or receiver privacy. + +Although server separation is mentioned in BIP 78, no specification exists to deploy them. This document specifies one. The opportunity to make the protocol asynchronous is also taken. + +The protocols in this document reuse BIP 78's BIP 21 URI parameters in order to reduce the size of v2 URIs and their QR code representations. It also provides a downgrade mechanism for unsecured payjoin relay to support v1 senders without modification. A timeout parameter is introduced better coordinate the synchronous v1 protocol. + +==Specification== + +===Overview=== + +Instead of a public http endpoint, this scheme allows a streaming client to act as a reciever. Requests are relayed via a server hosting , and symmetric cryptography for security. Without a replacement for secured networking, the relay could steal funds. Aside from a pre-shared secret and relayed networking, the PSBT protocol takes the same form as the existing BIP 78 spec. + +===Basic scheme=== + +The recipient first generates a 256-bit key psk. This pre-shared key will be the basis of end to end encryption over the relay. + +Rather than hosting a public server, they may allocate a subdirectory from to the http relay and start a streaming session to receive messages. This allocation includes the first 8 characters of the hash of their PSK as an identifier where they can be reached by another client. They await a payjoin request on this session. Out of band, they share a BIP 21[^5] payjoin uri including the relay endpoint in the pj query parameter and the pre-shared key in a new psk query parameter. + +The sender constructs their request containing a PSBT and optional parameters as in BIP 78. They construct an encrypted an authenticated payload from this data. The resulting ciphertext ensures message secrecy and integrity when sent to the recipient by the relay hosted pj endpoint. + +The pay-to-endpoint proceeds as in BIP 78. The sender's request is relayed to the receiver over their streaming session via the relay allocation. Messages are secured by symmetric cryptography rather than TLS or Onion routing session key. + +===V2 Payjoin Protocol=== + +Payjoin v2 messages use [[bip-0370.mediawiki|BIP 370 PSBT v2]] format to simplify PSBT mutation and obsolete the transaction finalizer. + +Assuming the receiver has already allocated space according to the [[#allocation|allocation protocol]] the relay, the payjoin protocol follows these steps. Steps required only when using a relay are prefixed [relay]. + +* The receiver of the payment, pre-shares a [[bip-0021.mediawiki|BIP 21 URI]] to the sender with a parameter pj= describing a payjoin endpoint and parameter psk= with 256-bit secret key. +* The sender creates a complete signed PSBT. We call this the Fallback PSBT, akin to BIP 78's Original PSBT. This Fallback PSBT and optional sender parameters are encrypted then authenticated with the psk using symmetric encryption and is transmitted to the payjoin endpoint. +* [relay] If the receiver is online, the relay transmits the payload to the reciver, else it responds with a success code notifying the sender that the receiver is offline. +* The receiver processes the payload, modifies the PSBT invalidating sender signatures. It updates it to include its signed inputs and outputs. It signs its inputs. We call this the Payjoin PSBT, akin to BIP 78's Payjoin proposal PSBT. It responds with the Payjoin PSBT encrypted then authenticated under psk. +* [relay] The relay awaits a connection from the sender. Upon connection, it relays the encrypted Payjoin PSBT to the sender. +* The sender validates the Payjoin PSBT, signs his inputs broadcasts the transaction to the Bitcoin network. We call this transaction Payjoin transaction. + +The Fallback Payload is sent in an HTTP POST request body, base64 serialized, with text/plain in the Content-Type HTTP header and Content-Length set correctly. +The Payjoin PSBT is sent in the HTTP response body, base64 serialized with HTTP code 200. + +To ensure compatibility with web-wallets and browser-based-tools, all responses (including errors) must contain the HTTP header Access-Control-Allow-Origin: *. + +Because the payloads themselves are encrypted, the protcol is safe to transmit over unsecured network protocols. Senders MAY accept a url representing unencrypted, unauthenticated connections. + +The Fallback PSBT MUST: +* Have all the witnessUTXO or nonWitnessUTXO information filled in. +* Be signed. +* Be broadcastable. + + +The Fallback PSBT MAY: +* Have outputs unrelated to the payment for batching purpose. + +The Payjoin PSBT MUST: +* Use all the inputs from the Fallback PSBT. +* Use all the outputs which do not belongs to the receiver from the original PSBT. + +* Only fill the witnessUTXO or nonWitnessUTXO for the additional inputs. + +The Payjoin PSBT sender MAY: +* Add, remove or modify Fallback PSBT outputs under the control of the receiver (i.e. not sender change). + +The Payjoin 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 transaction. + +===Serverless Relay Allocation Protocol=== + +A relay hosts both an HTTP server to service BIP 78 requests from the sender and a streaming server with WebTransport. The relay protocol is inspired by TURN. + +Relay allocation and usage takes the following steps + +* First, the client contacts a Relay server with an "Allocate" request. The Allocate request asks the relay to allocate some of its resources for the client so that it may contact a peer. If allocation is possible, the server allocates an address for the client to use as a relay, and sends the client an "Allocation Successful" response, which contains an "allocated relayed transport address " subdirectory located at the TURN server. +* Second, the client sends in a CreatePermissions request to the Relay server to create a permissions check system for peer-server communications. In other words, when a sender is finally contacted and sends information back to the Relay to be relayed to client, the Relay uses the permissions to verify that the peer-to-TURN server communication is valid (by checking psk signature). +* A receiver enrolls at the relay's allocation endpoint including relevant authentication headers to prevent DoS. An API token, proof of work, ecash, or payment of a lightning invoice could all impose cost to prevent DoS +* The relay responds with an allocation identifier subdirectory +* Upon receiving a POST request to payjoin, the server relays the request to the receiver, otherwise it holds onto it until it starts a session with the server again +* A sender who went offline after receiving success response but "receiver unavailable" should make another request to the relay when it comes online and be pushed any updates at the time of their arrival from the server. + +===BIP21 payjoin parameters=== + +This proposal is defining the following new [[bip-0021.mediawiki|BIP 21 URI]] parameters: +* dl=: Represents an deadline after which the sender will post the fallback transaction. Exclude for asynchronous operation of the protocol. + +===Optional query parameters=== + +When the payjoin sender posts the original PSBT to the receiver, he can optionally specify the following HTTP query string parameters: + +* v=, the version number of the payjoin protocol that the sender is using. This version is 2. + +===Improvements=== + +====Offline Asynchronous Payjoins==== + +The relay may hold a request for an offline payjoin peer until that peer comes online. However, the BIP 78 spec recommends broadcasting request PSBTs in the case of an offline counterparty. Doing so exposes a naïve, surveillance-vulnerable transaction which payjoin intends to avoid. Storing such requests without requring client authentication may create a vulnerability to relay DoS attacks. More research needs to be done before such a protocol can be recommended. + +The existing BIP 78 protocol has to be synchronous only for "interactive" endpoints which may be vulnerable to probing attacks. They can cover this tradeoff by demanding a fallback transaction that would not preserve privacy the same way as a payjoin. They could specify a deadline after which they will broadcast this fallback with a new deadline dl= parameter. + +===Noteworthy details=== + +====Backwards Compatibility==== + +The receivers are advertising payjoin capabilities through [[bip-0021.mediawiki|BIP21's URI Scheme]]. + +Senders not supporting payjoin will just ignore the pj variable and thus, will proceed to normal payment. + +Receivers may allow v1 senders to send unencrypted payloads to the relay. Payjoin relayed this way should enable pjos=0 so that these v1 sender's disable output substitution across a relay since the v1 messages are neither encrypted nor authenticated. The relay protocol should carry as normal, bundling HTTP header, query, and body information to send to the receiver. + +====Attack vectors==== + +Since relays store arbitrary encrypted payloads to the tragedy of the commons and denial of service attacks. Relay operators may impose an authentication requirement or proof of work before they provide relay service. + +Since psk is a symmetric key, the first message containing the sender's original PSBT does not have forward secrecy. + +Since the Fallback transaction is valid, even in the asynchronous setting where dl= is not specified, the receiver may broadcast it and lose out on ambiguous privacy protection from payjoin. + +====Network Privacy==== + +Peers will only see the IP address of the relay but not their peer's. Relays may be made available via Tor hidden service in addition to IP to allow either of the peers to protect their IP with Tor without forcing the other to use it too. From 3df3f51bf2e9145ede6cf751f45bde95f083bee9 Mon Sep 17 00:00:00 2001 From: DanGould Date: Sat, 12 Aug 2023 16:49:05 -0400 Subject: [PATCH 02/50] Include mailing list feedback --- bip-???-payjoin-v2.mediawiki | 272 +++++++++++++++++++++++++---------- 1 file changed, 200 insertions(+), 72 deletions(-) diff --git a/bip-???-payjoin-v2.mediawiki b/bip-???-payjoin-v2.mediawiki index 0e3b33e4ba..5c74ac1b3c 100644 --- a/bip-???-payjoin-v2.mediawiki +++ b/bip-???-payjoin-v2.mediawiki @@ -1,142 +1,270 @@
   BIP: ???
-  Title: Serverless Payjoin
+  Layer: Applications
+  Title: Payjoin Version 2: Serverless Payjoin
   Author: Dan Gould 
-  Replaces: 78
   Status: Draft
+  Replaces: 78
   Type: Standards Track
-  Created: 2023-04-08
+  Created: 2023-08-08
   License: BSD-2-Clause
 
==Abstract== -This document proposes a second version of the payjoin protocol described in BIP 78, allowing full payjoin receiver functionality including payment output substitution without the requirement to host a secure public endpoint. This requirement is replace with network protocols available in all modern web browsers. +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 them to host a secure public endpoint. This requirement is replaced with an untrusted third-party relay and streaming clients which communicate using an asynchronous protocol and authenticated, encrypted payloads. -===Copyright=== +==Copyright== This BIP is licensed under the 2-clause BSD license. ==Motivation== -Payjoin[^1] 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."[^2] Breaking that common-input ownership assumption requires contributions from multiple owners via interaction, namely hosting a server endpoint secured by a certificate on the receiving side either via TLS or Tor onion hidden service. Because the protocol is synchronous, both sender and reciever must be online to payjoin. These problems of convenience have been identified as the greatest barriers to widespread payjoin adoption.[^3] +Payjoin 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." Breaking that common-input ownership assumption and others requires input from multiple owners. Cooperative transaction construction also increases transaction throughput by providing new opportunity for payment batching and transaction cut-through. + +Version 1 coordinates payjoins over a public server endpoint secured by either TLS or Tor onion hidden service hosted by the receiver. Version 1 is synchronous, so both sender and reciever must be online simultaneously to payjoin. Both requirements present significant barriers for all but sophisticated server operators or those wallets with complex Tor integration. These barriers are [[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-January/018358.html|regarded]] as limits to payjoin adoption. + +The primary goal of this proposal is to provide a practical coordination mechanism to be adopted in a vast majority of wallet environments. This is realized as a simple protocol built on bitcoin URI requests, web standards, common crypto, and minimal dependencies. + +===Relation to BIP 78 (Payjoin version 1)=== -===Relation to BIP 78 (Payjoin v1)=== +The message payloads in this version parrallel those used in BIP 78 while being encapsulated in authenticated encryption, forgoing HTTP messaging for WebTransport streaming of asynchronus interactions, and leveraging PSBT version 2. -The BIP 78 standard allows for an [[#|unsecured payjoin server|]] to operate separately from the so-called "payment server" which generates [[bip-0021.mediawiki|BIP 21]] request URIs. Because BIP 78 messages are neither authenticated nor encrypted a malicious unsecured payjoin server is able to modify the Payjoin PSBT in flight, thus requiring [[payment output substitition]] to be disabled. Output substitition 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 substition without compromising sender or receiver privacy. +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 Payjoin PSBT in flight, thus requiring payment output substitition to be disabled. Output substitition 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 substition while using a relay without compromising sender or receiver privacy. -Although server separation is mentioned in BIP 78, no specification exists to deploy them. This document specifies one. The opportunity to make the protocol asynchronous is also taken. +Although unsecured payjoin server separation is mentioned in BIP 78, no known specification or implementation of one exists. This document specifies one to be backwards compatible with 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 relay stealing funds. -The protocols in this document reuse BIP 78's BIP 21 URI parameters in order to reduce the size of v2 URIs and their QR code representations. It also provides a downgrade mechanism for unsecured payjoin relay to support v1 senders without modification. A timeout parameter is introduced better coordinate the synchronous v1 protocol. +The protocols in this document reuse BIP 78's BIP 21 URI parameters. A Fallback PSBT timeout parameter is introduced which may also help coordinate the synchronous version 1 protocol. + +===Relation to Stowaway=== + +[[https://code.samourai.io/wallet/ExtLibJ/-/blob/develop/doc/cahoots/STOWAWAY.md|Stowaway]] is a payjoin coordination mechanism which depends on Tor, a third-party relay, and the [[https://samouraiwallet.com/paynym|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 the wallet. Payjoin version 2 also supports asynchronous messaging, in contrast to online Stowaway's synchronous HTTP-based 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=== -Instead of a public http endpoint, this scheme allows a streaming client to act as a reciever. Requests are relayed via a server hosting , and symmetric cryptography for security. Without a replacement for secured networking, the relay could steal funds. Aside from a pre-shared secret and relayed networking, the PSBT protocol takes the same form as the existing BIP 78 spec. +Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP endpoint, this scheme allows a WebTransport client to enroll with a relay server to receive payjoin. Relays may optionally require an authorization credential before allocating resources in order to prevent DoS attacks. Sender and receiver payloads are buffered at the relay to support asynchronous interaction. Authenticated encryption prevents the relay from snooping on message contents or forging messages. Aside from a application layer authenticate encryption and relayed asynchronus networking, the version 2 messaging takes much the same form as the existing BIP 78 specification. ===Basic scheme=== -The recipient first generates a 256-bit key psk. This pre-shared key will be the basis of end to end encryption over the relay. - -Rather than hosting a public server, they may allocate a subdirectory from to the http relay and start a streaming session to receive messages. This allocation includes the first 8 characters of the hash of their PSK as an identifier where they can be reached by another client. They await a payjoin request on this session. Out of band, they share a BIP 21[^5] payjoin uri including the relay endpoint in the pj query parameter and the pre-shared key in a new psk query parameter. - -The sender constructs their request containing a PSBT and optional parameters as in BIP 78. They construct an encrypted an authenticated payload from this data. The resulting ciphertext ensures message secrecy and integrity when sent to the recipient by the relay hosted pj endpoint. +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 relay. -The pay-to-endpoint proceeds as in BIP 78. The sender's request is relayed to the receiver over their streaming session via the relay allocation. Messages are secured by symmetric cryptography rather than TLS or Onion routing session key. +Rather than hosting a public server, they start a streaming session to receive messages and allocate a subdirectory from which to relay messages. The first message must include their pubkey to be enrolled as a subdirectory identifier. The next message streamed from the relay to sender includes the enrolled subdirectory payjoin endpoint with the pubkey as identifying subdirectory. After enrollment, they await a payjoin request on a session identified by the subdirectory. Out of band, the receiver shares a [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki|BIP 21]] payjoin uri including the relay endpoint in the pj= query parameter. -===V2 Payjoin Protocol=== +The sender constructs an encrypted and authenticated payload containing a PSBT and optional parameters similar to BIP 78. The resulting ciphertext ensures message secrecy and integrity when streamed to the recipient by the relay-hosted subdirectory pj= endpoint. -Payjoin v2 messages use [[bip-0370.mediawiki|BIP 370 PSBT v2]] format to simplify PSBT mutation and obsolete the transaction finalizer. +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 relay subdirectory. -Assuming the receiver has already allocated space according to the [[#allocation|allocation protocol]] the relay, the payjoin protocol follows these steps. Steps required only when using a relay are prefixed [relay]. +===Payjoin version 2 messaging=== -* The receiver of the payment, pre-shares a [[bip-0021.mediawiki|BIP 21 URI]] to the sender with a parameter pj= describing a payjoin endpoint and parameter psk= with 256-bit secret key. -* The sender creates a complete signed PSBT. We call this the Fallback PSBT, akin to BIP 78's Original PSBT. This Fallback PSBT and optional sender parameters are encrypted then authenticated with the psk using symmetric encryption and is transmitted to the payjoin endpoint. -* [relay] If the receiver is online, the relay transmits the payload to the reciver, else it responds with a success code notifying the sender that the receiver is offline. -* The receiver processes the payload, modifies the PSBT invalidating sender signatures. It updates it to include its signed inputs and outputs. It signs its inputs. We call this the Payjoin PSBT, akin to BIP 78's Payjoin proposal PSBT. It responds with the Payjoin PSBT encrypted then authenticated under psk. -* [relay] The relay awaits a connection from the sender. Upon connection, it relays the encrypted Payjoin PSBT to the sender. -* The sender validates the Payjoin PSBT, signs his inputs broadcasts the transaction to the Bitcoin network. We call this transaction Payjoin transaction. +Payjoin v2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki|BIP 370 PSBT v2]] format to fascilitate PSBT mutation. -The Fallback Payload is sent in an HTTP POST request body, base64 serialized, with text/plain in the Content-Type HTTP header and Content-Length set correctly. -The Payjoin PSBT is sent in the HTTP response body, base64 serialized with HTTP code 200. +The payjoin version 2 protocol takes the following steps: -To ensure compatibility with web-wallets and browser-based-tools, all responses (including errors) must contain the HTTP header Access-Control-Allow-Origin: *. +- The recipient sends their payjoin pubkey and optional authentication credential according to [[#receiver-relay-enrollment|receiver relay enrollment]] protocol. It may go offline and replay enrollment to come back online. +- Out of band, the receiver of the payment, shares a bitcoin URI with the sender including a pj= query parameter describing the relay subdirectory endpoint parameter with base64-uri encoded pubkey. To support version 1 senders the relay 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 PSBT according to [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]] formatted as PSBTv2. We call this the Fallback PSBT. This Fallback PSBT, optional sender parameters, and cryptographic keys are encrypted and authenticated according to the Secp256k1 IK handshake and streamed to the relay subdirectory endpoint. +- The sender awaits a response from the relay stream containing an encrypted Payjoin PSBT as Message B. It can replay the Fallback PSBT Mesasge A to request a response if it goes offline. +- The request is stored in the receiver's subdirectory buffer. +- Once the receiver is online, it awaits a stream of request updates from the relay. The receiver decrypts aund authenticates the payload then checks it according to [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. It updates it to include new signed inputs and outputs invalidating sender signatures, and may adjust the fee. We call this the Payjoin PSBT. +- It responds with the Payjoin PSBT encrypted then authenticated as Message B according to the Secp256k1 IK handshake. +- The relay awaits a connection from the sender if it goes offline. Upon connection, it relays the encrypted Payjoin PSBT to the sender. +- The sender validates the Payjoin PSBT according to [[#senders-payjoin-psbt-checklist|the sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network. -Because the payloads themselves are encrypted, the protcol is safe to transmit over unsecured network protocols. Senders MAY accept a url representing unencrypted, unauthenticated connections. +The encrypted Fallback PSBT and Payjoin PSBT payloads are sent as bytes. The Fallback PSBT MUST: -* Have all the witnessUTXO or nonWitnessUTXO information filled in. -* Be signed. -* Be broadcastable. - + +- Include complete UTXO data. +- Be signed. +- Exclude unnecessary fields such as global xpubs or keypath information. +- Set input and output Transaction Modifiable Flags to 1 +- Be broadcastable. The Fallback PSBT MAY: -* Have outputs unrelated to the payment for batching purpose. + +- Include outputs unrelated to the sender-receiver transfer for batching purposes. +- Set SIGHASH_SINGLE Transaction Modifiable Flags flags to 1 The Payjoin PSBT MUST: -* Use all the inputs from the Fallback PSBT. -* Use all the outputs which do not belongs to the receiver from the original PSBT. - -* Only fill the witnessUTXO or nonWitnessUTXO for the additional inputs. + +- Include all inputs from the Fallback PSBT. +- Include all outputs which do not belong to the receiver from the Fallback PSBT. +- Include complete UTXO data. The Payjoin PSBT sender MAY: -* Add, remove or modify Fallback PSBT outputs under the control of the receiver (i.e. not sender change). + +- Add, remove or modify Fallback PSBT outputs under the control of the receiver (i.e. not sender change). The Payjoin 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 transaction. -===Serverless Relay Allocation Protocol=== +- 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 transaction. + +===Receiver's Payjoin PSBT checklist=== + +Other than requiring PSBTv2 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]] + +===Sender's Payjoin PSBT checklist=== + +The version 2 sender's checklist is largely the same as the [[https://github.com/bitcoin/bips/blob/master/bip-0078#senders-payjoin-proposal-checklist|the BIP 78 checklist]] with the exception that 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 headaches since it required the sender to add them back to the Payjoin proposal PSBT. Version 2 has no such requirement. + +===Relay interactions=== + +The Payjoin Relay provides a rendezvous point for sender and receiver to meet. It stores Payjoin payloads to support asynchronous communication. It is available on the open internet over HTTPS to accept both WebTransport for Payjoin version 2, accepting encrypted payloads, and optionally HTTP/1.1 to support backwards compatible Payjoin version 1 requests. + +===Receiver interactions=== + +====Relay enrollment==== + +Receivers must enroll to have resources allocated on a relay. Sessions may begin by having a receiver send the static pubkey to the relay. The receiver returns the subdirectory endpoint url with the final subdirectory as base64-uri encoded pubkey. Enrollment may be replayed in case the receiver goes offline. + +Optionally, before returning the uri the receiver may request an authentication token by presenting a message containing only the word Authenticate: after which the receiver is required to submit an Authenticate: including the token from the Relay out of band. If authentication fails an error is returned. + +In the case a relay is operated by an exchange, it may give out authentication tokens for users of its app, or may require some proof of work out of band. Tokens should be anonymous credentials from the relay describing the parameters of their authorization. Specific credentialing is out of the scope of this proposal. + +====Receiver Payjoin PSBT response==== + +The receiver streams the base64 Payjoin PSBT as encrypted bytes according to Secp256k1 IK. + +===Sender interactions=== + +The sender starts a WebTransport session with the relay at the Payjoin endpoint URI provided by the receiver. It sends the following payload and awaits a relayed response payload from the receiver. + +====Version 2 Fallback PSBT request==== + +The version 2 Fallback PSBT Payload is constructed in JSON before being encrypted as follows. + +
+{
+  "psbt": "",
+  "params": {
+      "param1": "",
+      "param2": "",
+      ...
+  }
+}
+
+ +The payload must be encrypted according to Secp256k1 IK. + +====Version 1 Fallback PSBT request==== + +The message should be the same as version 2 but unencrypted, as version 1 is unaware of encryption when using an unsecured payjoin server. The Relay should convert the PSBT to PSBTv2 and construct the JSON payload from the HTTP request body and optional query parameters. Upon receiving an unencrypted PSBTv2 response from a receiver, it should convert it to PSBTv0 for compatibility with BIP 78. + +===Asynchronous relay buffers=== + +Each receiver subdirectory on the relay server has a buffer for requests and one for responses. Each buffer updates listeners through awaitable events so that updates are immediately apparent to relevant client sessions. + +===BIP 21 receiver parameters=== + +A major benefit of BIP 78 payjoin over other coordination mechanisms is its compatibility with the universal BIP 21 bitcoin URI standard. + +This proposal defines the following new [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki|BIP 21 URI]] parameters: + +- exp: represents a request expiration after which the receiver reserves the right to broadcast the Fallback and ignore requests. This is only necessary for receivers who only support synchonous execution of the protocol, like automated payment processors. + +BIP 78's BIP 21 payjoin parameters are also valid for version 2. + +===Optional sender parameters=== + +When the payjoin sender posts the original PSBT to the receiver, it can optionally 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 & fallback=== + +The relay may hold a request for an offline payjoin peer until that peer comes online. However, the BIP 78 spec recommends broadcasting request 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 a fallback transaction that would not preserve privacy the same way as a payjoin. BIP 21 URI can communicate a request expiration to alleviate both of these problems. Receivers may specify a deadline after which they will broadcast this fallback with a new expiration parameter exp=. + +===WebTransport=== + +Many transport protocols are good candidates for Serverless Payjoin functionality, but WebTransport stands out in its ability to stream and take advantage of QUIC's performance in mobile environments. In developing this BIP, serverless payjoin proofs of concept using TURN, HTTP/1.1 long polling, WebSockets, Magic Wormhole, and Nostr have been made. Streaming allows the relay to have more granular and asynchronous understanding of the state of the peers, and this protcol is designed specifically to address the shortcomings of an HTTP protocol's requirement to receive from a reliable, always-online connection. + +While WebTransport and HTTP/3 it is built on are relatively new, widespread support across browsers assures me that it is being accepted as a standard and even has a fallback to HTTP/2 environments. Being built on top of QUIC allows it to multiplex connections from a relay to multiple peers which may prove advantageous for later payjoin protocols between more than two participants contributing inputs, such as those used to fund a lightning node with channels from multiple sources in one transaction, or those with threat models more similar to ZeroLink CoinJoin. + +While Nostr is fascinating from the perspective of censorship resistance, the backwards compatibility with Payjoin v1 would mean only custom Nostr Payjoin relays exposing an https endpoint would be suitable. Nostr transport is also limited by the performance of WebSockets, being an abstraction on top of that protocol. There is nothing stopping a new version of this protocol or a NIP making Payjoin version 2 possible over Nostr should Payjoin censorship become a bottleneck in the way of adoption. + +WebTransport is already shipped in both Firefox, Chrome, h3 in Rust, Go, and all popular languages. There is also [[https://w3c.github.io/p2p-webtransport/|a working draft for full P2P WebTransport]] without any relay, which a future payjoin protocol may make use of. + +===Secp256k1 IK inspired handshake=== + +<-- 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/NKpsk0/|IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static noise keys are only to be used once per session + +====Noise IK pattern==== + +
+NKpsk0:
+  <- s
+  ...
+  -> e, es, s, ss
+  <- e, ee, se
+
+ +====BIP 21 pre-shared public key==== + +The recipient shares the first handshake message containing the receiver's static public key, i.e. s in Noise framework parlance. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5|base64url]] encoding so it can be provided in the pj= parameter + +====Fallback PSBT Message A==== + +Sender derives an ephemeral secp256k1 key pair for this session. Sender derives a shared secret using Elliptic Cureve Diffie-Hellman (ECDH) key agreement. The sender derives a symmetric key + +Message A includes a sender ephemeral key, DH shared secret derived from the sender's ephemeral key and the receiver's static key, the sender's static key s, and a shared ss DH secret derived from both sender and receiver's static keys. + +Message A, sent by the sender, benefits from receiver authentication and is resistant to Key Compromise Impersonation. Message contents benefit from message secrecy and some forward secrecy since ephemeral keys are used. The compromise of the receivers's (but not the sender's) static private keys,even at a later date, will lead to message contents being decrypted by an attacker. + +====Payjoin PSBT Message B==== + +Message B is encreypted and authenticated using the shared secrets based off of per-session ephemeral keys. -A relay hosts both an HTTP server to service BIP 78 requests from the sender and a streaming server with WebTransport. The relay protocol is inspired by TURN. +The receiver's shared secrets -Relay allocation and usage takes the following steps +The sender can be confident that message B has sender authentication and is Key Compromise Impersonation resistant. If the sender receives a valid message from the receiver, then the receiver must have sent that message, unless the keys have been compromised before this session. If the responder's long-term static keys were previously compromised, the later compromise of the initiator's long-term static keys can lead to message contents being decrypted by an active attacker, should that attacker also have forged the initiator's ephemeral key during the session -* First, the client contacts a Relay server with an "Allocate" request. The Allocate request asks the relay to allocate some of its resources for the client so that it may contact a peer. If allocation is possible, the server allocates an address for the client to use as a relay, and sends the client an "Allocation Successful" response, which contains an "allocated relayed transport address " subdirectory located at the TURN server. -* Second, the client sends in a CreatePermissions request to the Relay server to create a permissions check system for peer-server communications. In other words, when a sender is finally contacted and sends information back to the Relay to be relayed to client, the Relay uses the permissions to verify that the peer-to-TURN server communication is valid (by checking psk signature). -* A receiver enrolls at the relay's allocation endpoint including relevant authentication headers to prevent DoS. An API token, proof of work, ecash, or payment of a lightning invoice could all impose cost to prevent DoS -* The relay responds with an allocation identifier subdirectory -* Upon receiving a POST request to payjoin, the server relays the request to the receiver, otherwise it holds onto it until it starts a session with the server again -* A sender who went offline after receiving success response but "receiver unavailable" should make another request to the relay when it comes online and be pushed any updates at the time of their arrival from the server. +====Secp256k1==== -===BIP21 payjoin parameters=== +Secp256k1 should be used in place of Noise's specified Curve25519 DH functions because of it's availability in bitcoin contexts. -This proposal is defining the following new [[bip-0021.mediawiki|BIP 21 URI]] parameters: -* dl=: Represents an deadline after which the sender will post the fallback transaction. Exclude for asynchronous operation of the protocol. +====ChaCha20Poly1305 AEAD==== -===Optional query parameters=== +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 seems to be making its way into bitcoin by way of [[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. -When the payjoin sender posts the original PSBT to the receiver, he can optionally specify the following HTTP query string parameters: +===PSBT Version 2=== -* v=, the version number of the payjoin protocol that the sender is using. This version is 2. +The PSBT version 1 protocol was replaced because it was not designed to have inputs and outputs be mutated. Payjoin mutates the PSBT, so BIP 78 uses a hack where a new PSBT is created by the receiver instead of mutating it. This can cause some strange behaviors from signers who don't know where to look to find the scripts that they are accountable for. PSBT version 2 makes mutating a PSBT's inputs and outputs trivial. It also eliminates the transaction finalization step. Receivers who do not understand PSBT version 1 may choose to reject Payjoin version 1 requests and only support PSBT version 2. -===Improvements=== +===Attack vectors=== -====Offline Asynchronous Payjoins==== +Since relays store arbitrary encrypted payloads to the tragedy of the commons and denial of service attacks. Relay operators may impose an authentication requirement before they provide relay service to receivers to mitigate such attacks. -The relay may hold a request for an offline payjoin peer until that peer comes online. However, the BIP 78 spec recommends broadcasting request PSBTs in the case of an offline counterparty. Doing so exposes a naïve, surveillance-vulnerable transaction which payjoin intends to avoid. Storing such requests without requring client authentication may create a vulnerability to relay DoS attacks. More research needs to be done before such a protocol can be recommended. +Since we make use of 0-RTT IK, the first message containing the sender's original PSBT has minimal forward secrecy. If the receiver's key is compromised, this message containing the Fallback PSBT could be read. -The existing BIP 78 protocol has to be synchronous only for "interactive" endpoints which may be vulnerable to probing attacks. They can cover this tradeoff by demanding a fallback transaction that would not preserve privacy the same way as a payjoin. They could specify a deadline after which they will broadcast this fallback with a new deadline dl= parameter. +Since the Fallback PSBT is valid, even where exp= is specified, the receiver may broadcast it and lose out on ambiguous privacy protection from payjoin at any time. Though unfortunate, this is the typical bitcoin transaction flow today anyhow. -===Noteworthy details=== +===Network privacy=== -====Backwards Compatibility==== +Unlike BIP 78 implementations, sender and receiver peers will only see the IP address of the relay, not their peer's. Relays may be made available via Tor hidden service or Oblivious HTTP in addition to IP / DNS to allow either of the peers to protect their IP from the relay with without requiring both peers to use additional network security dependencies. -The receivers are advertising payjoin capabilities through [[bip-0021.mediawiki|BIP21's URI Scheme]]. +==Backwards compatibility== -Senders not supporting payjoin will just ignore the pj variable and thus, will proceed to normal payment. +The receivers advertise payjoin capabilities through [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki|BIP21's URI Scheme]]. -Receivers may allow v1 senders to send unencrypted payloads to the relay. Payjoin relayed this way should enable pjos=0 so that these v1 sender's disable output substitution across a relay since the v1 messages are neither encrypted nor authenticated. The relay protocol should carry as normal, bundling HTTP header, query, and body information to send to the receiver. +Senders not supporting payjoin will just ignore the pj= parameter and proceed to typical address-based transaction flows. req-pj= may be used to compel payjoin. -====Attack vectors==== +Receivers may choose to support version 1 payloads. Version 2 payjoin URIs should enable pjos=0 so that these v1 senders disable output substitution since the v1 messages are neither encrypted nor authenticated, putting them at risk for man-in-the-middle attacks otherwise. The relay protocol should carry on as normal, validating based on HTTP headers and constructing an unencrypted Version 2 payload from optional query parameters, and PSBT in the body. -Since relays store arbitrary encrypted payloads to the tragedy of the commons and denial of service attacks. Relay operators may impose an authentication requirement or proof of work before they provide relay service. +The BIP 78 error messages are already JSON formatted, so it made sense to rely on the same dependency for these payloads and error messages. -Since psk is a symmetric key, the first message containing the sender's original PSBT does not have forward secrecy. +==Reference implementation== -Since the Fallback transaction is valid, even in the asynchronous setting where dl= is not specified, the receiver may broadcast it and lose out on ambiguous privacy protection from payjoin. +An early proof of concept draft reference implementation can be found at https://github.com/payjoin/rust-payjoin/pull/78. It implements an asynchronous payment flow using WebSockets using PSBTv1 without encryption. Another reference can be found at https://github.com/payjoin/rust-payjoin/pull/21 which uses HTTP long polling for transport and Noise NNpsk0 for crypto. Recently, I've come to realize the rationale for WebTransport, PSBTv2, and Noise IK substitutions and am working on an implementation including this exact specification, but wanted to get early feedback on this design in the spirit of BIP 2. -====Network Privacy==== +==Acknowledgements== -Peers will only see the IP address of the relay but not their peer's. Relays may be made available via Tor hidden service in addition to IP to allow either of the peers to protect their IP with Tor without forcing the other to use it too. +Thank you to OpenSats for funding this pursuit, to Human Rights Foundation for putting a bounty on it and funding invaluable BOB Space space support, who I owe a thank you to as well. Thank you to Ethan Heilman, Nicolas Dorier, Kukks, nopara73, Kristaps Kaupe, Kixunil, /dev/fd0/, Craig Raw, Mike Schmidt, Murch, Dávid Molnár, Lucas Ontiviero, waxwing, Christopher Allen, Symphonic, and countless twitter plebs for feedback that has turned this idea from concept into draft, to Mike Jarmuz for suggesting that I write a BIP, and to Satsie for writing the "All About BIPS" zine which I've referenced a number of times in the drafting process. Thanks to Armin Sabouri, Ron Stoner, and Johns Beharry for hacking on the first iOS Payjoin receiver and uncovering the problem that this solves in the first place. \ No newline at end of file From 936d0e7fd99f54fdae0c1e792bb256348d3dcb99 Mon Sep 17 00:00:00 2001 From: DanGould Date: Wed, 1 Nov 2023 16:05:39 -0400 Subject: [PATCH 03/50] Include TABConf feedback --- bip-???-payjoin-v2.mediawiki | 169 ++++++++++++++--------------------- 1 file changed, 66 insertions(+), 103 deletions(-) diff --git a/bip-???-payjoin-v2.mediawiki b/bip-???-payjoin-v2.mediawiki index 5c74ac1b3c..83c67a0aaa 100644 --- a/bip-???-payjoin-v2.mediawiki +++ b/bip-???-payjoin-v2.mediawiki @@ -12,7 +12,7 @@ ==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 them to host a secure public endpoint. This requirement is replaced with an untrusted third-party relay and streaming clients which communicate using an asynchronous protocol and authenticated, encrypted payloads. +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 them to host a secure public endpoint. This requirement is replaced with an untrusted third-party relay and HTTP clients which communicate using an asynchronous protocol and authenticated, encrypted payloads. Authenticated encryption depends only on cryptographic primitives available in Bitcoin Core. Requests use Oblivious HTTP to prevent the relay and payjoin peers from linking requests to client IP addresses. ==Copyright== @@ -22,29 +22,29 @@ This BIP is licensed under the 2-clause BSD license. Payjoin 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." Breaking that common-input ownership assumption and others requires input from multiple owners. Cooperative transaction construction also increases transaction throughput by providing new opportunity for payment batching and transaction cut-through. -Version 1 coordinates payjoins over a public server endpoint secured by either TLS or Tor onion hidden service hosted by the receiver. Version 1 is synchronous, so both sender and reciever must be online simultaneously to payjoin. Both requirements present significant barriers for all but sophisticated server operators or those wallets with complex Tor integration. These barriers are [[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-January/018358.html|regarded]] as limits to payjoin 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 synchronous, requiring both sender and reciever 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 develoepers [[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 to be adopted in a vast majority of wallet environments. This is realized as a simple protocol built on bitcoin URI requests, web standards, common crypto, and minimal dependencies. +The primary goal of this proposal is to provide a practical coordination mechanism adaptable to a majority of wallet environments. This is realized as a simple protocol built on bitcoin URI requests, web standards, common crypto, and minimal dependencies. ===Relation to BIP 78 (Payjoin version 1)=== -The message payloads in this version parrallel those used in BIP 78 while being encapsulated in authenticated encryption, forgoing HTTP messaging for WebTransport streaming of asynchronus interactions, and leveraging PSBT version 2. +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. This protocol also upgrades to PSBT version 2 to simplify transaction construction. 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 Payjoin PSBT in flight, thus requiring payment output substitition to be disabled. Output substitition 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 substition while using a relay without compromising sender or receiver privacy. -Although unsecured payjoin server separation is mentioned in BIP 78, no known specification or implementation of one exists. This document specifies one to be backwards compatible with 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 relay stealing funds. +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 relay 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 relay stealing funds. -The protocols in this document reuse BIP 78's BIP 21 URI parameters. A Fallback PSBT timeout parameter is introduced which may also help coordinate the synchronous version 1 protocol. +The protocols in this document reuse BIP 78's BIP 21 URI parameters. A Original PSBT timeout parameter is introduced which may also help coordinate the synchronous version 1 protocol. ===Relation to Stowaway=== -[[https://code.samourai.io/wallet/ExtLibJ/-/blob/develop/doc/cahoots/STOWAWAY.md|Stowaway]] is a payjoin coordination mechanism which depends on Tor, a third-party relay, and the [[https://samouraiwallet.com/paynym|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 the wallet. Payjoin version 2 also supports asynchronous messaging, in contrast to online Stowaway's synchronous HTTP-based 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. +[[https://code.samourai.io/wallet/ExtLibJ/-/blob/develop/doc/cahoots/STOWAWAY.md|Stowaway]] is a payjoin coordination mechanism which depends on Tor, a third-party relay, and the [[https://samouraiwallet.com/paynym|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 a WebTransport client to enroll with a relay server to receive payjoin. Relays may optionally require an authorization credential before allocating resources in order to prevent DoS attacks. Sender and receiver payloads are buffered at the relay to support asynchronous interaction. Authenticated encryption prevents the relay from snooping on message contents or forging messages. Aside from a application layer authenticate encryption and relayed asynchronus networking, the version 2 messaging takes much the same form as the existing BIP 78 specification. +Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP endpoint, this scheme allows an HTTP client to enroll with a store-and-forward relay server to receive payjoin. Relays may optionally require an authorization credential before allocating resources in order to prevent DoS attacks. Sender and receiver payloads are buffered at the relay to support asynchronous interaction. Authenticated encryption prevents the relay 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 relay to prevent metadata attacks. Aside from a application layer authenticated encryption and relayed asynchronus networking, the version 2 messaging takes much the same form as the existing BIP 78 specification. ===Basic scheme=== @@ -62,19 +62,17 @@ Payjoin v2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.m The payjoin version 2 protocol takes the following steps: -- The recipient sends their payjoin pubkey and optional authentication credential according to [[#receiver-relay-enrollment|receiver relay enrollment]] protocol. It may go offline and replay enrollment to come back online. +- The recipient sends their payjoin pubkey and optional authentication credential according to [[#relay-enrollment|receiver relay enrollment]] protocol. It may go offline and replay enrollment to come back online. - Out of band, the receiver of the payment, shares a bitcoin URI with the sender including a pj= query parameter describing the relay subdirectory endpoint parameter with base64-uri encoded pubkey. To support version 1 senders the relay 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 PSBT according to [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]] formatted as PSBTv2. We call this the Fallback PSBT. This Fallback PSBT, optional sender parameters, and cryptographic keys are encrypted and authenticated according to the Secp256k1 IK handshake and streamed to the relay subdirectory endpoint. -- The sender awaits a response from the relay stream containing an encrypted Payjoin PSBT as Message B. It can replay the Fallback PSBT Mesasge A to request a response if it goes offline. -- The request is stored in the receiver's subdirectory buffer. -- Once the receiver is online, it awaits a stream of request updates from the relay. The receiver decrypts aund authenticates the payload then checks it according to [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. It updates it to include new signed inputs and outputs invalidating sender signatures, and may adjust the fee. We call this the Payjoin PSBT. -- It responds with the Payjoin PSBT encrypted then authenticated as Message B according to the Secp256k1 IK handshake. -- The relay awaits a connection from the sender if it goes offline. Upon connection, it relays the encrypted Payjoin PSBT to the sender. +- The sender creates a valid version 2 PSBT satisfying the [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. We call this the Original PSBT. This Original PSBT, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#original-psbt-request|Original PSBT Request]] is sent to the relay's OHTTP Gateway. +- The sender continues to replay this request in order to await a response from the relay containing a Payjoin PSBT. It stops after expiry. +- The request is stored in the relay's subdirectory buffer. +- Once the receiver is online, it sends /receiverequests to await updates from the relay subdirectory. The receiver decrypts and authenticates the response which and checks it according to [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. It updates it to include new signed inputs and outputs invalidating sender signatures, and may adjust the fee. We call this the Payjoin PSBT. +- The Payjoin PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and sent to the relay's OHTTP Gateway. +- The relay awaits a request from the sender if it goes offline. Upon request, it relays the encrypted Payjoin PSBT. - The sender validates the Payjoin PSBT according to [[#senders-payjoin-psbt-checklist|the sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network. -The encrypted Fallback PSBT and Payjoin PSBT payloads are sent as bytes. - -The Fallback PSBT MUST: +The Original PSBT MUST: - Include complete UTXO data. - Be signed. @@ -82,80 +80,63 @@ The Fallback PSBT MUST: - Set input and output Transaction Modifiable Flags to 1 - Be broadcastable. -The Fallback PSBT MAY: +The Original PSBT MAY: - Include outputs unrelated to the sender-receiver transfer for batching purposes. - Set SIGHASH_SINGLE Transaction Modifiable Flags flags to 1 The Payjoin PSBT MUST: -- Include all inputs from the Fallback PSBT. -- Include all outputs which do not belong to the receiver from the Fallback PSBT. +- 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 Payjoin PSBT sender MAY: -- Add, remove or modify Fallback PSBT outputs under the control of the receiver (i.e. not sender change). +- Add, remove or modify Original PSBT outputs under the control of the receiver (i.e. not sender change). The Payjoin 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 transaction. -===Receiver's Payjoin PSBT checklist=== - -Other than requiring PSBTv2 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]] - -===Sender's Payjoin PSBT checklist=== - -The version 2 sender's checklist is largely the same as the [[https://github.com/bitcoin/bips/blob/master/bip-0078#senders-payjoin-proposal-checklist|the BIP 78 checklist]] with the exception that 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 headaches since it required the sender to add them back to the Payjoin proposal PSBT. Version 2 has no such requirement. - -===Relay interactions=== - -The Payjoin Relay provides a rendezvous point for sender and receiver to meet. It stores Payjoin payloads to support asynchronous communication. It is available on the open internet over HTTPS to accept both WebTransport for Payjoin version 2, accepting encrypted payloads, and optionally HTTP/1.1 to support backwards compatible Payjoin version 1 requests. - -===Receiver interactions=== +====Enroll Messaging==== -====Relay enrollment==== +The client discovers the OHTTP gateway's key configuration via an HTTP OPTIONS request to the gateway's URI. -Receivers must enroll to have resources allocated on a relay. Sessions may begin by having a receiver send the static pubkey to the relay. The receiver returns the subdirectory endpoint url with the final subdirectory as base64-uri encoded pubkey. Enrollment may be replayed in case the receiver goes offline. +Receivers must enroll to have resources allocated on a relay. Sessions may begin by having a receiver send the static pubkey to the relay. The receiver returns the subdirectory endpoint url with the final subdirectory as base64-uri encoded pubkey AND an Oblivious HTTP Key Configuration. Enrollment may be replayed in case the receiver goes offline. Optionally, before returning the uri the receiver may request an authentication token by presenting a message containing only the word Authenticate: after which the receiver is required to submit an Authenticate: including the token from the Relay out of band. If authentication fails an error is returned. In the case a relay is operated by an exchange, it may give out authentication tokens for users of its app, or may require some proof of work out of band. Tokens should be anonymous credentials from the relay describing the parameters of their authorization. Specific credentialing is out of the scope of this proposal. -====Receiver Payjoin PSBT response==== +====Send Messaging==== -The receiver streams the base64 Payjoin PSBT as encrypted bytes according to Secp256k1 IK. +The version 2 Original PSBT is placed in an HTTP POST request body, base64 serialized, with text/plain in the Content-Type HTTP header and Content-Length set correctly, as in version 1, before being encoded into BHTTP and encrypted according to the HPKE protocol. This Original PSBT BHTTP Request is then encrypted according to the HPKE, generating an ephemeral keypair `e` from which it derives a shared secret `es` with the receiver's key `s`. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Original PSBT BHTTP Request and serialized ephemeral key `e`'s pubkey as associated data using ChaCha20Poly1305. A payload is constructed by concatenating the ephemeral pubkey, the nonce, and the ciphertext. This payload is then sent to the relay in an OHTTP request encapsulating the binary payload. -===Sender interactions=== +The relay's OHTTP Gateway decapsulates the OHTTP request, decrypts the payload, and forwards the BHTTP POST request to the receiver's internal subdirectory endpoint which stores the HPKE encrypted payload to be forwarded to the receiver. The relay's OHTTP Gateway then awaits a response from the receiver's subdirectory endpoint, encapsulates it, and responds according to OHTTP. -The sender starts a WebTransport session with the relay at the Payjoin endpoint URI provided by the receiver. It sends the following payload and awaits a relayed response payload from the receiver. +====Receive Messaging==== -====Version 2 Fallback PSBT request==== +The receiver sends a GET request to the path of the subdirectory followed by `/receive`. This request is encapsulated in OHTTP. It awaits an OHTTP response from the relay containing the BHTTP request from the sender with status code 200 OK, or sends a new OHTTP request after receiving 202 ACCEPTED notifying the receiver that the relay has not yet received an request from the sender. -The version 2 Fallback PSBT Payload is constructed in JSON before being encrypted as follows. +Once an Original PSBT Payload is decrypted and checked according to the list, the receiver may respond with a Payjoin PSBT. The receiver encrypts the PSBT according to the HPKE protocol, generating an ephemeral keypair `e` from which it derives a shared secret `ee` with the sender's key `e` from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Payjoin PSBT and serialized receiver ephemeral key `e`'s pubkey as associated data using ChaCha20Poly1305. A payload is constructed by concatenating the ephemeral pubkey, the nonce, and the ciphertext. This payload is then sent to the relay in an OHTTP request encapsulating the binary payload as a POST message to the subdirectory followed by `/receive`. -
-{
-  "psbt": "",
-  "params": {
-      "param1": "",
-      "param2": "",
-      ...
-  }
-}
-
+===Receiver's Payjoin PSBT checklist=== -The payload must be encrypted according to Secp256k1 IK. +Other than requiring PSBTv2 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]] -====Version 1 Fallback PSBT request==== +===Sender's Payjoin PSBT checklist=== -The message should be the same as version 2 but unencrypted, as version 1 is unaware of encryption when using an unsecured payjoin server. The Relay should convert the PSBT to PSBTv2 and construct the JSON payload from the HTTP request body and optional query parameters. Upon receiving an unencrypted PSBTv2 response from a receiver, it should convert it to PSBTv0 for compatibility with BIP 78. +The version 2 sender's checklist is largely the same as the [[https://github.com/bitcoin/bips/blob/master/bip-0078#senders-payjoin-proposal-checklist|the BIP 78 checklist]] with the exception that 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 headaches since it required the sender to add them back to the Payjoin proposal PSBT. Version 2 has no such requirement. + +===Relay interactions=== + +The Payjoin Relay provides a rendezvous point for sender and receiver to meet. It stores Payjoin payloads to support asynchronous communication. It must only accept OHTTP requests with an OHTTP Gateway for Payjoin version 2, accepting encrypted payloads. It may optionally accept HTTP/1.1 POST requests without HTTP to enrolled subdirectories to support backwards compatible Payjoin version 1 requests. ===Asynchronous relay buffers=== -Each receiver subdirectory on the relay server has a buffer for requests and one for responses. Each buffer updates listeners through awaitable events so that updates are immediately apparent to relevant client sessions. +Each receiver subdirectory on the relay server has a buffer for requests and one for responses. Each buffer updates listeners through awaitable events so that updates are immediately apparent upon client request. ===BIP 21 receiver parameters=== @@ -163,7 +144,7 @@ A major benefit of BIP 78 payjoin over other coordination mechanisms is its comp This proposal defines the following new [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki|BIP 21 URI]] parameters: -- exp: represents a request expiration after which the receiver reserves the right to broadcast the Fallback and ignore requests. This is only necessary for receivers who only support synchonous execution of the protocol, like automated payment processors. +- exp: represents a request expiration 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. BIP 78's BIP 21 payjoin parameters are also valid for version 2. @@ -177,79 +158,63 @@ BIP 78's optional query parameters are also valid as version 2 parameters. ==Rationale== -===Request expiration & fallback=== +===Request expiration & Original PSBT=== The relay may hold a request for an offline payjoin peer until that peer comes online. However, the BIP 78 spec recommends broadcasting request 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 a fallback transaction that would not preserve privacy the same way as a payjoin. BIP 21 URI can communicate a request expiration to alleviate both of these problems. Receivers may specify a deadline after which they will broadcast this fallback with a new expiration parameter exp=. - -===WebTransport=== - -Many transport protocols are good candidates for Serverless Payjoin functionality, but WebTransport stands out in its ability to stream and take advantage of QUIC's performance in mobile environments. In developing this BIP, serverless payjoin proofs of concept using TURN, HTTP/1.1 long polling, WebSockets, Magic Wormhole, and Nostr have been made. Streaming allows the relay to have more granular and asynchronous understanding of the state of the peers, and this protcol is designed specifically to address the shortcomings of an HTTP protocol's requirement to receive from a reliable, always-online connection. +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 Original PSBT from which a valid payment transaction may be extracted that would not preserve privacy the same way as a payjoin. BIP 21 URI 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=. -While WebTransport and HTTP/3 it is built on are relatively new, widespread support across browsers assures me that it is being accepted as a standard and even has a fallback to HTTP/2 environments. Being built on top of QUIC allows it to multiplex connections from a relay to multiple peers which may prove advantageous for later payjoin protocols between more than two participants contributing inputs, such as those used to fund a lightning node with channels from multiple sources in one transaction, or those with threat models more similar to ZeroLink CoinJoin. +===HTTP=== -While Nostr is fascinating from the perspective of censorship resistance, the backwards compatibility with Payjoin v1 would mean only custom Nostr Payjoin relays exposing an https endpoint would be suitable. Nostr transport is also limited by the performance of WebSockets, being an abstraction on top of that protocol. There is nothing stopping a new version of this protocol or a NIP making Payjoin version 2 possible over Nostr should Payjoin censorship become a bottleneck in the way of adoption. +HTTP is ubiquitous. Using simple HTTP polling allows even Bitcoin Core to consider an implementation. Unlike a WebSockets protocol, plain HTTP is eligible to enjoy metadata protection from Oblivious HTTP. -WebTransport is already shipped in both Firefox, Chrome, h3 in Rust, Go, and all popular languages. There is also [[https://w3c.github.io/p2p-webtransport/|a working draft for full P2P WebTransport]] without any relay, which a future payjoin protocol may make use of. +===Oblivious HTTP=== -===Secp256k1 IK inspired handshake=== +OHTTP protects sender and receiver IP addresses from both the relay and one another. This makes it more difficult for a relay to correlate many payjoin transactions with a specific IP addresses by intersection. -<-- 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/NKpsk0/|IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static noise keys are only to be used once per session - -====Noise IK pattern==== - -
-NKpsk0:
-  <- s
-  ...
-  -> e, es, s, ss
-  <- e, ee, se
-
+OHTTP relays can be run as basic HTTP proxies from wallet providers. Getting OHTTP Gateway configurations does require additional communication between each client and the relay, but this can be done over Tor (hidden service even), a VPN, or provided by a trusted third party like the wallet provider. -====BIP 21 pre-shared public key==== +===Message Padding=== -The recipient shares the first handshake message containing the receiver's static public key, i.e. s in Noise framework parlance. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5|base64url]] encoding so it can be provided in the pj= parameter +TODO ??? TODO -====Fallback PSBT Message A==== +All cyphertexts should be padded to the same length to prevent traffic analysis. This is not yet implemented in the reference implementation. -Sender derives an ephemeral secp256k1 key pair for this session. Sender derives a shared secret using Elliptic Cureve Diffie-Hellman (ECDH) key agreement. The sender derives a symmetric key +===Secp256k1 Hybrid Public Key Encryption=== -Message A includes a sender ephemeral key, DH shared secret derived from the sender's ephemeral key and the receiver's static key, the sender's static key s, and a shared ss DH secret derived from both sender and receiver's static keys. +Hybrid Public Key Encryption 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 v2 appication specific configuration to use DHKEM(Secp256k1, HKDF-SHA256) and ChaCha20Poly1305 AEAD. -Message A, sent by the sender, benefits from receiver authentication and is resistant to Key Compromise Impersonation. Message contents benefit from message secrecy and some forward secrecy since ephemeral keys are used. The compromise of the receivers's (but not the sender's) static private keys,even at a later date, will lead to message contents being decrypted by an attacker. - -====Payjoin PSBT Message B==== - -Message B is encreypted and authenticated using the shared secrets based off of per-session ephemeral keys. - -The receiver's shared secrets - -The sender can be confident that message B has sender authentication and is Key Compromise Impersonation resistant. If the sender receives a valid message from the receiver, then the receiver must have sent that message, unless the keys have been compromised before this session. If the responder's long-term static keys were previously compromised, the later compromise of the initiator's long-term static keys can lead to message contents being decrypted by an active attacker, should that attacker also have forged the initiator's ephemeral key during the session +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/NKpsk0/|IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static keys shared in URIs must only for a single session. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5|base64url]] encoding as a subdirectory of the relay server in the pj= parameter. ====Secp256k1==== -Secp256k1 should be used in place of Noise's specified Curve25519 DH functions because of it's availability in bitcoin contexts. +Secp256k1 should be used in place of HPKE's specified DH functions because of it's availability in bitcoin contexts. A proposal to standardize its inclusion may be appropriate. ====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 seems to be making its way into bitcoin by way of [[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 secure and widely available in bitcoin contexts. + ===PSBT Version 2=== The PSBT version 1 protocol was replaced because it was not designed to have inputs and outputs be mutated. Payjoin mutates the PSBT, so BIP 78 uses a hack where a new PSBT is created by the receiver instead of mutating it. This can cause some strange behaviors from signers who don't know where to look to find the scripts that they are accountable for. PSBT version 2 makes mutating a PSBT's inputs and outputs trivial. It also eliminates the transaction finalization step. Receivers who do not understand PSBT version 1 may choose to reject Payjoin version 1 requests and only support PSBT version 2. ===Attack vectors=== -Since relays store arbitrary encrypted payloads to the tragedy of the commons and denial of service attacks. Relay operators may impose an authentication requirement before they provide relay service to receivers to mitigate such attacks. +Since relays store arbitrary encrypted payloads they are vulnerable to the tragedy of the commons and denial of service attacks. Relay operators may impose an authentication requirement before they provide relay service to receivers to mitigate such attacks. -Since we make use of 0-RTT IK, the first message containing the sender's original PSBT has minimal forward secrecy. If the receiver's key is compromised, this message containing the Fallback PSBT could be read. +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. -Since the Fallback PSBT is valid, even where exp= is specified, the receiver may broadcast it and lose out on ambiguous privacy protection from payjoin at any time. Though unfortunate, this is the typical bitcoin transaction flow today anyhow. +Since the Original PSBT is valid, even where exp= is specified, the receiver may broadcast it and lose out on savings from payment batching and privacy protection from payjoin structure at any time. Though unfortunate, this failure mode is the typical bitcoin transaction flow today anyhow. -===Network privacy=== +===Network privacy=== -Unlike BIP 78 implementations, sender and receiver peers will only see the IP address of the relay, not their peer's. Relays may be made available via Tor hidden service or Oblivious HTTP in addition to IP / DNS to allow either of the peers to protect their IP from the relay with without requiring both peers to use additional network security dependencies. +Oblivious HTTP must be used to protect the IP address of both sender and receiver from the relay. This requires an additional key configuration to be shared in the bip21 URI and for the relay to support Oblivious HTTP. A secp256k1 HPKE OHTTP configuration should be used to leverage the crypto already in use for the payjoin protocol. + +Unlike BIP 78 implementations, sender and receiver peers will only see the IP address of the relay, not their peer's. Relays may aditionally be made available via Tor hidden service to allow either of the peers to protect their IP from the relay with without OHTTP. ==Backwards compatibility== @@ -257,9 +222,7 @@ The receivers advertise payjoin capabilities through [[https://github.com/bitcoi Senders not supporting payjoin will just ignore the pj= parameter and proceed to typical address-based transaction flows. req-pj= may be used to compel payjoin. -Receivers may choose to support version 1 payloads. Version 2 payjoin URIs should enable pjos=0 so that these v1 senders disable output substitution since the v1 messages are neither encrypted nor authenticated, putting them at risk for man-in-the-middle attacks otherwise. The relay protocol should carry on as normal, validating based on HTTP headers and constructing an unencrypted Version 2 payload from optional query parameters, and PSBT in the body. - -The BIP 78 error messages are already JSON formatted, so it made sense to rely on the same dependency for these payloads and error messages. +Receivers may choose to support version 1 payloads. Version 2 payjoin URIs should enable pjos=0 so that these v1 senders disable output substitution since the v1 messages are neither encrypted nor authenticated, putting them at risk for man-in-the-middle attacks otherwise. The relay protocol should carry on as normal, responding to `/receive` get requests instead with this version 1 request as BHTTP in an OHTTP response. The receiver should POST version 1 Payjoin PSBTs to `/receive` to respond to these version 1 senders within 30 seconds to respond to the sender's request. ==Reference implementation== @@ -267,4 +230,4 @@ An early proof of concept draft reference implementation can be found at https:/ ==Acknowledgements== -Thank you to OpenSats for funding this pursuit, to Human Rights Foundation for putting a bounty on it and funding invaluable BOB Space space support, who I owe a thank you to as well. Thank you to Ethan Heilman, Nicolas Dorier, Kukks, nopara73, Kristaps Kaupe, Kixunil, /dev/fd0/, Craig Raw, Mike Schmidt, Murch, Dávid Molnár, Lucas Ontiviero, waxwing, Christopher Allen, Symphonic, and countless twitter plebs for feedback that has turned this idea from concept into draft, to Mike Jarmuz for suggesting that I write a BIP, and to Satsie for writing the "All About BIPS" zine which I've referenced a number of times in the drafting process. Thanks to Armin Sabouri, Ron Stoner, and Johns Beharry for hacking on the first iOS Payjoin receiver and uncovering the problem that this solves in the first place. \ No newline at end of file +Thank you to OpenSats for funding this pursuit, to Human Rights Foundation for putting a bounty on it and funding invaluable BOB Space space support, who I owe a thank you to as well. Thank you to Ethan Heilman, Nicolas Dorier, Kukks, nopara73, Kristaps Kaupe, Kixunil, /dev/fd0/, Craig Raw, Mike Schmidt, Murch, Dávid Molnár, Lucas Ontiviero, Waxwing, Christopher Allen, Symphonic, Steve Meyers, Sjors Provost, Andrew Chow, and countless plebs for feedback that has turned this idea from concept into draft, to Mike Jarmuz for suggesting that I write a BIP, and to Satsie for writing the "All About BIPS" zine which I've referenced a number of times in the drafting process. Thanks to Armin Sabouri, Ron Stoner, and Johns Beharry for hacking on the first iOS Payjoin receiver and uncovering the problem that this solves in the first place. From 4069db51ba2589faf79cf7389c68c1d094dd8c64 Mon Sep 17 00:00:00 2001 From: DanGould Date: Wed, 13 Dec 2023 21:29:42 -0500 Subject: [PATCH 04/50] Include padding --- bip-???-payjoin-v2.mediawiki | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bip-???-payjoin-v2.mediawiki b/bip-???-payjoin-v2.mediawiki index 83c67a0aaa..db95066085 100644 --- a/bip-???-payjoin-v2.mediawiki +++ b/bip-???-payjoin-v2.mediawiki @@ -176,9 +176,7 @@ OHTTP relays can be run as basic HTTP proxies from wallet providers. Getting OHT ===Message Padding=== -TODO ??? TODO - -All cyphertexts should be padded to the same length to prevent traffic analysis. This is not yet implemented in the reference implementation. +All cyphertexts should be padded to the same length of 7168 bytes to prevent traffic analysis. This is sufficient size for most transaction PSBTs without exceeding the 8KB limit of many HTTP/1.1 web servers. ===Secp256k1 Hybrid Public Key Encryption=== From 45daed4ef1c64b48053d32342896d3bdb120e10d Mon Sep 17 00:00:00 2001 From: DanGould Date: Fri, 15 Dec 2023 14:09:36 -0500 Subject: [PATCH 05/50] Include production reference implementation --- bip-???-payjoin-v2.mediawiki | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bip-???-payjoin-v2.mediawiki b/bip-???-payjoin-v2.mediawiki index db95066085..ae1a3f92b9 100644 --- a/bip-???-payjoin-v2.mediawiki +++ b/bip-???-payjoin-v2.mediawiki @@ -220,12 +220,16 @@ The receivers advertise payjoin capabilities through [[https://github.com/bitcoi Senders not supporting payjoin will just ignore the pj= parameter and proceed to typical address-based transaction flows. req-pj= may be used to compel payjoin. -Receivers may choose to support version 1 payloads. Version 2 payjoin URIs should enable pjos=0 so that these v1 senders disable output substitution since the v1 messages are neither encrypted nor authenticated, putting them at risk for man-in-the-middle attacks otherwise. The relay protocol should carry on as normal, responding to `/receive` get requests instead with this version 1 request as BHTTP in an OHTTP response. The receiver should POST version 1 Payjoin PSBTs to `/receive` to respond to these version 1 senders within 30 seconds to respond to the sender's request. +Receivers may choose to support version 1 payloads. Version 2 payjoin URIs should enable pjos=0 so that these v1 senders disable output substitution since the v1 messages are neither encrypted nor authenticated, putting them at risk for man-in-the-middle attacks otherwise. The relay 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 Payjoin PSBTs to the same subdirectory as in version 2 to respond to these version 1 senders within 30 seconds to respond to the sender's request. ==Reference implementation== -An early proof of concept draft reference implementation can be found at https://github.com/payjoin/rust-payjoin/pull/78. It implements an asynchronous payment flow using WebSockets using PSBTv1 without encryption. Another reference can be found at https://github.com/payjoin/rust-payjoin/pull/21 which uses HTTP long polling for transport and Noise NNpsk0 for crypto. Recently, I've come to realize the rationale for WebTransport, PSBTv2, and Noise IK substitutions and am working on an implementation including this exact specification, but wanted to get early feedback on this design in the spirit of BIP 2. +An production reference implementation client can be found at https://crates.io/crates/payjoin-cli/0.0.2-alpha. Source code for the clients, directory server, and development kit may be found here: https://github.com/payjoin/rust-payjoin. Source code for Oblivous HTTP relays may be found here https://github.com/payjoin/ohttp-relay. The reference implementation implements an asynchronous payment flow using HTTP using PSBTv1 with encryption and Oblivious HTTP and may be configured to the following independent production relays: + +A payjoin directory server is run by the Payjoin Dev Kit team on https://payjo.in. + +Independent Oblivious HTTP relays are run by Obscura VPN at https://ohttp-relay.obscuravpn.io/payjoin and by BOB Spaces at https://pj.bobspacebkk.com. ==Acknowledgements== -Thank you to OpenSats for funding this pursuit, to Human Rights Foundation for putting a bounty on it and funding invaluable BOB Space space support, who I owe a thank you to as well. Thank you to Ethan Heilman, Nicolas Dorier, Kukks, nopara73, Kristaps Kaupe, Kixunil, /dev/fd0/, Craig Raw, Mike Schmidt, Murch, Dávid Molnár, Lucas Ontiviero, Waxwing, Christopher Allen, Symphonic, Steve Meyers, Sjors Provost, Andrew Chow, and countless plebs for feedback that has turned this idea from concept into draft, to Mike Jarmuz for suggesting that I write a BIP, and to Satsie for writing the "All About BIPS" zine which I've referenced a number of times in the drafting process. Thanks to Armin Sabouri, Ron Stoner, and Johns Beharry for hacking on the first iOS Payjoin receiver and uncovering the problem that this solves in the first place. +Thank you to OpenSats for funding this pursuit, to Human Rights Foundation for putting a bounty on it and funding invaluable BOB Space space support, who I owe a thank you to as well. Thank you to Ethan Heilman, Nicolas Dorier, Kukks, nopara73, Kristaps Kaupe, Kixunil, /dev/fd0/, Craig Raw, Mike Schmidt, Murch, Dávid Molnár, Lucas Ontiviero, Waxwing, Christopher Allen, Symphonic, Steve Meyers, Sjors Provost, Ava Chow, jbesraa, and countless plebs for feedback that has turned this idea from concept into draft, to Mike Jarmuz for suggesting that I write a BIP, and to Satsie for writing the "All About BIPS" zine which I've referenced a number of times in the drafting process. Thanks to Armin Sabouri, Ron Stoner, and Johns Beharry for hacking on the first iOS Payjoin receiver and uncovering the problem that this solves in the first place. From b593c457c9bda5a47ad2f91f96585178058669e8 Mon Sep 17 00:00:00 2001 From: DanGould Date: Wed, 27 Dec 2023 10:59:49 -0500 Subject: [PATCH 06/50] Adopt BIP-77 for payjoin v2 --- bip-???-payjoin-v2.mediawiki => bip-0077.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename bip-???-payjoin-v2.mediawiki => bip-0077.mediawiki (99%) diff --git a/bip-???-payjoin-v2.mediawiki b/bip-0077.mediawiki similarity index 99% rename from bip-???-payjoin-v2.mediawiki rename to bip-0077.mediawiki index ae1a3f92b9..a75f95c206 100644 --- a/bip-???-payjoin-v2.mediawiki +++ b/bip-0077.mediawiki @@ -1,5 +1,5 @@
-  BIP: ???
+  BIP: 77
   Layer: Applications
   Title: Payjoin Version 2: Serverless Payjoin
   Author: Dan Gould 

From 6becb34a5e134246f5376515c221bea7b6886a0d Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Wed, 6 Mar 2024 10:55:06 -0500
Subject: [PATCH 07/50] Distinguish payjoin directory from OHTTP Relay

---
 bip-0077.mediawiki | 72 +++++++++++++++++++++++-----------------------
 1 file changed, 36 insertions(+), 36 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index a75f95c206..47f773a235 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -12,7 +12,7 @@
 
 ==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 them to host a secure public endpoint. This requirement is replaced with an untrusted third-party relay and HTTP clients which communicate using an asynchronous protocol and authenticated, encrypted payloads. Authenticated encryption depends only on cryptographic primitives available in Bitcoin Core. Requests use Oblivious HTTP to prevent the relay and payjoin peers from linking requests to client IP addresses.
+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 them to host a secure public endpoint. This requirement is replaced with an untrusted third-party directory and HTTP clients which communicate using an asynchronous protocol and authenticated, encrypted payloads. Authenticated encryption depends only on cryptographic primitives available in Bitcoin Core. Requests use Oblivious HTTP to prevent the directory and payjoin peers from linking requests to client IP addresses.
 
 ==Copyright==
 
@@ -30,9 +30,9 @@ The primary goal of this proposal is to provide a practical coordination mechani
 
 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. This protocol also upgrades to PSBT version 2 to simplify transaction construction.
 
-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 Payjoin PSBT in flight, thus requiring payment output substitition to be disabled. Output substitition 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 substition while using a relay without compromising sender or receiver privacy.
+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 Payjoin PSBT in flight, thus requiring payment output substitition to be disabled. Output substitition 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 substition while using a directory relay 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 relay 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 relay stealing funds.
+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 stealing funds.
 
 The protocols in this document reuse BIP 78's BIP 21 URI parameters. A Original PSBT timeout parameter is introduced which may also help coordinate the synchronous version 1 protocol.
 
@@ -44,17 +44,17 @@ The protocols in this document reuse BIP 78's BIP 21 URI parameters. A Original
 
 ===Overview===
 
-Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP endpoint, this scheme allows an HTTP client to enroll with a store-and-forward relay server to receive payjoin. Relays may optionally require an authorization credential before allocating resources in order to prevent DoS attacks. Sender and receiver payloads are buffered at the relay to support asynchronous interaction. Authenticated encryption prevents the relay 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 relay to prevent metadata attacks. Aside from a application layer authenticated encryption and relayed asynchronus networking, the version 2 messaging takes much the same form as the existing BIP 78 specification.
+Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP endpoint, this scheme allows an HTTP client to enroll with a store-and-forward directory server to receive payjoin. 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 a application layer authenticated encryption and relayed asynchronus networking, the 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 relay.
+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, they start a streaming session to receive messages and allocate a subdirectory from which to relay messages. The first message must include their pubkey to be enrolled as a subdirectory identifier. The next message streamed from the relay to sender includes the enrolled subdirectory payjoin endpoint with the pubkey as identifying subdirectory. After enrollment, they await a payjoin request on a session identified by the subdirectory. Out of band, the receiver shares a [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki|BIP 21]] payjoin uri including the relay endpoint in the pj= query parameter.
+Rather than hosting a public server, they start a session to receive messages and allocate a subdirectory from which to relay messages. The first message must include their pubkey to be enrolled as a subdirectory identifier. The next message from the directory to sender includes the enrolled subdirectory payjoin endpoint with the pubkey as identifying subdirectory. After enrollment, they await a payjoin request on a session identified by the subdirectory. 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.
 
-The sender constructs an encrypted and authenticated payload containing a PSBT and optional parameters similar to BIP 78. The resulting ciphertext ensures message secrecy and integrity when streamed to the recipient by the relay-hosted subdirectory pj= endpoint.
+The sender constructs an encrypted and authenticated payload containing a PSBT and optional parameters similar to BIP 78. The resulting ciphertext ensures message secrecy and integrity when passed to the recipient 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 relay subdirectory.
+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.
 
 ===Payjoin version 2 messaging===
 
@@ -62,14 +62,14 @@ Payjoin v2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.m
 
 The payjoin version 2 protocol takes the following steps:
 
-- The recipient sends their payjoin pubkey and optional authentication credential according to [[#relay-enrollment|receiver relay enrollment]] protocol. It may go offline and replay enrollment to come back online.
-- Out of band, the receiver of the payment, shares a bitcoin URI with the sender including a pj= query parameter describing the relay subdirectory endpoint parameter with base64-uri encoded pubkey. To support version 1 senders the relay 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 2 PSBT satisfying the [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. We call this the Original PSBT. This Original PSBT, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#original-psbt-request|Original PSBT Request]] is sent to the relay's OHTTP Gateway.
-- The sender continues to replay this request in order to await a response from the relay containing a Payjoin PSBT. It stops after expiry.
-- The request is stored in the relay's subdirectory buffer.
-- Once the receiver is online, it sends /receiverequests to await updates from the relay subdirectory. The receiver decrypts and authenticates the response which and checks it according to [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. It updates it to include new signed inputs and outputs invalidating sender signatures, and may adjust the fee. We call this the Payjoin PSBT.
-- The Payjoin PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and sent to the relay's OHTTP Gateway.
-- The relay awaits a request from the sender if it goes offline. Upon request, it relays the encrypted Payjoin PSBT.
+- The recipient sends their payjoin pubkey and optional authentication credential according to [[#directory-enrollment|receiver directory enrollment]] protocol to receive a subdirectory allocation. It may go offline and replay enrollment to come back online.
+- Out of band, the receiver of the payment, shares a bitcoin URI with the sender including a pj= query parameter including the subdirectory as a base64-uri encoded pubkey. 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. An ohttp= parameter containing the directory's base64-url Key Config should also be provided.
+- The sender creates a valid version 2 PSBT satisfying the [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. We call this the Original PSBT. This Original PSBT, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#original-psbt-request|Original PSBT Request]] is sent to the directory's OHTTP Gateway.
+- The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry.
+- The request is stored in the subdirectory.
+- Once the receiver is online, it sends /receiverequests to await updates from the subdirectory. The receiver decrypts and authenticates the response which it checks according to [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. It updates the Original PSBT to include new signed inputs and outputs, invalidating sender signatures, and may adjust the fee. The result is called the Payjoin PSBT.
+- The Payjoin PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and sent to the directory's OHTTP Gateway.
+- The directory awaits a request from the sender if it goes offline. Upon request, it relays the encrypted Payjoin PSBT.
 - The sender validates the Payjoin PSBT according to [[#senders-payjoin-psbt-checklist|the sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network.
 
 The Original PSBT MUST:
@@ -104,23 +104,23 @@ The Payjoin PSBT MUST NOT:
 
 The client discovers the OHTTP gateway's key configuration via an HTTP OPTIONS request to the gateway's URI.
 
-Receivers must enroll to have resources allocated on a relay. Sessions may begin by having a receiver send the static pubkey to the relay. The receiver returns the subdirectory endpoint url with the final subdirectory as base64-uri encoded pubkey AND an Oblivious HTTP Key Configuration. Enrollment may be replayed in case the receiver goes offline.
+Receivers must enroll to have resources allocated on a directory. Sessions may begin by having a receiver send the static pubkey to the directory. The receiver returns the subdirectory endpoint url with the final subdirectory as base64-uri encoded pubkey AND an Oblivious HTTP Key Configuration. Enrollment may be replayed in case the receiver goes offline.
 
-Optionally, before returning the uri the receiver may request an authentication token by presenting a message containing only the word Authenticate:  after which the receiver is required to submit an Authenticate:  including the token from the Relay out of band. If authentication fails an error is returned.
+Optionally, before returning the uri the receiver may request an authentication token by presenting a message containing only the word Authenticate:  after which the receiver is required to submit an Authenticate:  including the token from the directory out of band. If authentication fails an error is returned.
 
-In the case a relay is operated by an exchange, it may give out authentication tokens for users of its app, or may require some proof of work out of band. Tokens should be anonymous credentials from the relay describing the parameters of their authorization. Specific credentialing is out of the scope of this proposal.
+In the case a directory is operated by an exchange, it may give out authentication tokens for users of its app, or may require some proof of work out of band. Tokens should be anonymous credentials from the directory describing the parameters of their authorization. Specific credentialing is out of the scope of this proposal.
 
 ====Send Messaging====
 
-The version 2 Original PSBT is placed in an HTTP POST request body, base64 serialized, with text/plain in the Content-Type HTTP header and Content-Length set correctly, as in version 1, before being encoded into BHTTP and encrypted according to the HPKE protocol. This Original PSBT BHTTP Request is then encrypted according to the HPKE, generating an ephemeral keypair `e` from which it derives a shared secret `es` with the receiver's key `s`. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Original PSBT BHTTP Request and serialized ephemeral key `e`'s pubkey as associated data using ChaCha20Poly1305. A payload is constructed by concatenating the ephemeral pubkey, the nonce, and the ciphertext. This payload is then sent to the relay in an OHTTP request encapsulating the binary payload.
+The version 2 Original PSBT is placed in an HTTP POST request body, base64 serialized, with text/plain in the Content-Type HTTP header and Content-Length set correctly, as in version 1, before being encoded into BHTTP and encrypted according to the HPKE protocol. This Original PSBT BHTTP Request is then encrypted according to the HPKE, generating an ephemeral keypair `e` from which it derives a shared secret `es` with the receiver's key `s`. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Original PSBT BHTTP Request and serialized ephemeral key `e`'s pubkey as associated data using ChaCha20Poly1305. A payload is constructed by concatenating the ephemeral pubkey, the nonce, and the ciphertext. This payload is then sent to the directory in an OHTTP request encapsulating the binary payload.
 
-The relay's OHTTP Gateway decapsulates the OHTTP request, decrypts the payload, and forwards the BHTTP POST request to the receiver's internal subdirectory endpoint which stores the HPKE encrypted payload to be forwarded to the receiver. The relay's OHTTP Gateway then awaits a response from the receiver's subdirectory endpoint, encapsulates it, and responds according to OHTTP.
+The directory's OHTTP Gateway decapsulates the OHTTP request, decrypts the payload, and forwards the BHTTP POST request to the receiver's internal subdirectory endpoint which stores the HPKE encrypted payload to be forwarded to the receiver. The directory's OHTTP Gateway then awaits a response from the receiver's subdirectory endpoint, encapsulates it, and responds according to OHTTP.
 
 ====Receive Messaging====
 
-The receiver sends a GET request to the path of the subdirectory followed by `/receive`. This request is encapsulated in OHTTP. It awaits an OHTTP response from the relay containing the BHTTP request from the sender with status code 200 OK, or sends a new OHTTP request after receiving 202 ACCEPTED notifying the receiver that the relay has not yet received an request from the sender.
+The receiver sends a GET request to the path of the subdirectory followed by `/receive`. This request is encapsulated in OHTTP. It awaits an OHTTP response from the directory containing the BHTTP request from the sender with status code 200 OK, or sends a new OHTTP request after receiving 202 ACCEPTED notifying the receiver that the directory has not yet received an request from the sender.
 
-Once an Original PSBT Payload is decrypted and checked according to the list, the receiver may respond with a Payjoin PSBT. The receiver encrypts the PSBT according to the HPKE protocol, generating an ephemeral keypair `e` from which it derives a shared secret `ee` with the sender's key `e` from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Payjoin PSBT and serialized receiver ephemeral key `e`'s pubkey as associated data using ChaCha20Poly1305. A payload is constructed by concatenating the ephemeral pubkey, the nonce, and the ciphertext. This payload is then sent to the relay in an OHTTP request encapsulating the binary payload as a POST message to the subdirectory followed by `/receive`.
+Once an Original PSBT Payload is decrypted and checked according to the list, the receiver may respond with a Payjoin PSBT. The receiver encrypts the PSBT according to the HPKE protocol, generating an ephemeral keypair `e` from which it derives a shared secret `ee` with the sender's key `e` from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Payjoin PSBT and serialized receiver ephemeral key `e`'s pubkey as associated data using ChaCha20Poly1305. A payload is constructed by concatenating the ephemeral pubkey, the nonce, and the ciphertext. This payload is then sent to the directory in an OHTTP request encapsulating the binary payload as a POST message to the subdirectory followed by `/receive`.
 
 ===Receiver's Payjoin PSBT checklist===
 
@@ -130,13 +130,13 @@ Other than requiring PSBTv2 the receiver checklist is the same as the [[https://
 
 The version 2 sender's checklist is largely the same as the [[https://github.com/bitcoin/bips/blob/master/bip-0078#senders-payjoin-proposal-checklist|the BIP 78 checklist]] with the exception that 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 headaches since it required the sender to add them back to the Payjoin proposal PSBT. Version 2 has no such requirement.
 
-===Relay interactions===
+===Directory interactions===
 
-The Payjoin Relay provides a rendezvous point for sender and receiver to meet. It stores Payjoin payloads to support asynchronous communication. It must only accept OHTTP requests with an OHTTP Gateway for Payjoin version 2, accepting encrypted payloads. It may optionally accept HTTP/1.1 POST requests without HTTP to enrolled subdirectories to support backwards compatible Payjoin version 1 requests.
+The Payjoin Directory provides a rendezvous point for sender and receiver to meet. It stores Payjoin payloads to support asynchronous communication. It must only accept OHTTP requests with an OHTTP Gateway for Payjoin version 2, accepting encrypted payloads. It may optionally accept HTTP/1.1 POST requests without HTTP to enrolled subdirectories to support backwards compatible Payjoin version 1 requests.
 
-===Asynchronous relay buffers===
+===Subdirectories===
 
-Each receiver subdirectory on the relay server has a buffer for requests and one for responses. Each buffer updates listeners through awaitable events so that updates are immediately apparent upon client request.
+Each receiver subdirectory on the directory server has a buffer for requests and one for responses. Each buffer updates listeners through awaitable events so that updates are immediately apparent upon client request.
 
 ===BIP 21 receiver parameters===
 
@@ -160,7 +160,7 @@ BIP 78's optional query parameters are also valid as version 2 parameters.
 
 ===Request expiration & Original PSBT===
 
-The relay may hold a request for an offline payjoin peer until that peer comes online. However, the BIP 78 spec recommends broadcasting request PSBTs in the case of an offline counterparty. Doing so exposes a naïve, surveillance-vulnerable transaction which payjoin intends to avoid.
+The directory may hold a request for an offline payjoin peer until that peer comes online. However, the BIP 78 spec recommends broadcasting request 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  Original PSBT from which a valid payment transaction may be extracted that would not preserve privacy the same way as a payjoin. BIP 21 URI 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=. 
 
@@ -170,9 +170,9 @@ HTTP is ubiquitous. Using simple HTTP polling allows even Bitcoin Core to consid
 
 ===Oblivious HTTP===
 
-OHTTP protects sender and receiver IP addresses from both the relay and one another. This makes it more difficult for a relay to correlate many payjoin transactions with a specific IP addresses by intersection.
+OHTTP protects sender and receiver IP addresses from both one another and from the directory. This makes it more difficult for a directory to correlate many payjoin transactions with a specific IP addresses by intersection.
 
-OHTTP relays can be run as basic HTTP proxies from wallet providers. Getting OHTTP Gateway configurations does require additional communication between each client and the relay, but this can be done over Tor (hidden service even), a VPN, or provided by a trusted third party like the wallet provider.
+OHTTP relays can be run as basic HTTP proxies from wallet providers. Getting OHTTP Gateway configurations does require additional communication between each client and the directory, but this can be done over Tor (hidden service even), a VPN, or provided by a trusted third party like the wallet provider.
 
 ===Message Padding===
 
@@ -182,7 +182,7 @@ All cyphertexts should be padded to the same length of 7168 bytes to prevent tra
 
 Hybrid Public Key Encryption 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 v2 appication 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/NKpsk0/|IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static keys shared in URIs must only for a single session. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5|base64url]] encoding as a subdirectory of the relay server in the pj= parameter.
+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/NKpsk0/|IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static keys shared in URIs must only for a single session. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5|base64url]] encoding as a subdirectory of the directory server in the pj= parameter.
 
 ====Secp256k1====
 
@@ -202,7 +202,7 @@ The PSBT version 1 protocol was replaced because it was not designed to have inp
 
 ===Attack vectors===
 
-Since relays store arbitrary encrypted payloads they are vulnerable to the tragedy of the commons and denial of service attacks. Relay operators may impose an authentication requirement before they provide relay service to receivers to mitigate such attacks.
+Since directories store arbitrary encrypted payloads they are vulnerable to the tragedy of the commons and denial of service attacks. Directory operators may impose an authentication requirement before they allocate a subdirectory to receivers to mitigate such attacks.
 
 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.
 
@@ -210,9 +210,9 @@ Since the Original PSBT is valid, even where exp= is specified, the
 
 ===Network privacy=== 
 
-Oblivious HTTP must be used to protect the IP address of both sender and receiver from the relay. This requires an additional key configuration to be shared in the bip21 URI and for the relay to support Oblivious HTTP. A secp256k1 HPKE OHTTP configuration should be used to leverage the crypto already in use for the payjoin protocol.
+Oblivious HTTP must be used to protect the IP address of both sender and receiver from the directory. This requires an additional key configuration to be shared in the bip21 URI and for the directory to support Oblivious HTTP. A secp256k1 HPKE OHTTP configuration should be used to leverage the crypto already in use for the payjoin protocol.
 
-Unlike BIP 78 implementations, sender and receiver peers will only see the IP address of the relay, not their peer's. Relays may aditionally be made available via Tor hidden service to allow either of the peers to protect their IP from the relay with without OHTTP.
+Unlike BIP 78 implementations, sender and receiver peers will only see the IP address of the directory, not their peer's. Directories may aditionally be made available via Tor hidden service to allow either of the peers to protect their IP from the directory with without OHTTP.
 
 ==Backwards compatibility==
 
@@ -220,11 +220,11 @@ The receivers advertise payjoin capabilities through [[https://github.com/bitcoi
 
 Senders not supporting payjoin will just ignore the pj= parameter and proceed to typical address-based transaction flows. req-pj= may be used to compel payjoin. 
 
-Receivers may choose to support version 1 payloads. Version 2 payjoin URIs should enable pjos=0 so that these v1 senders disable output substitution since the v1 messages are neither encrypted nor authenticated, putting them at risk for man-in-the-middle attacks otherwise. The relay 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 Payjoin PSBTs to the same subdirectory as in version 2 to respond to these version 1 senders within 30 seconds to respond to the sender's request.
+Receivers may choose to support version 1 payloads. Version 2 payjoin URIs should enable pjos=0 so that these v1 senders disable output substitution since the v1 messages are neither encrypted nor authenticated, putting them at risk for man-in-the-middle attacks otherwise. 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 Payjoin PSBTs to the same subdirectory as in version 2 to respond to these version 1 senders within 30 seconds to respond to the sender's request.
 
 ==Reference implementation==
 
-An production reference implementation client can be found at https://crates.io/crates/payjoin-cli/0.0.2-alpha. Source code for the clients, directory server, and development kit may be found here: https://github.com/payjoin/rust-payjoin. Source code for Oblivous HTTP relays may be found here https://github.com/payjoin/ohttp-relay. The reference implementation implements an asynchronous payment flow using HTTP using PSBTv1 with encryption and Oblivious HTTP and may be configured to the following independent production relays:
+An production reference implementation client can be found at https://crates.io/crates/payjoin-cli/0.0.2-alpha. Source code for the clients, directory server, 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 implements an asynchronous payment flow using HTTP using PSBTv1 with encryption and Oblivious HTTP and may be configured to the following independent production relays:
 
 A payjoin directory server is run by the Payjoin Dev Kit team on https://payjo.in.
 

From 754e287d462a074de169e3943c69a6fc131a5500 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Wed, 6 Mar 2024 11:17:27 -0500
Subject: [PATCH 08/50] Detail OHTTP Key Configuration mechanism

---
 bip-0077.mediawiki | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 47f773a235..b7b098cd66 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -12,7 +12,7 @@
 
 ==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 them to host a secure public endpoint. This requirement is replaced with an untrusted third-party directory and HTTP clients which communicate using an asynchronous protocol and authenticated, encrypted payloads. Authenticated encryption depends only on cryptographic primitives available in Bitcoin Core. Requests use Oblivious HTTP to prevent the directory and payjoin peers from linking requests to client IP addresses.
+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 them to host a secure public endpoint. This requirement is replaced with an untrusted third-party directory and HTTP clients which 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==
 
@@ -50,7 +50,7 @@ Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP e
 
 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, they start a session to receive messages and allocate a subdirectory from which to relay messages. The first message must include their pubkey to be enrolled as a subdirectory identifier. The next message from the directory to sender includes the enrolled subdirectory payjoin endpoint with the pubkey as identifying subdirectory. After enrollment, they await a payjoin request on a session identified by the subdirectory. 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.
+Rather than hosting a public server, they start a session to receive messages and allocate a subdirectory from which to relay messages. The first message must include their pubkey to be enrolled as a subdirectory identifier. The next message from the directory to sender includes the enrolled subdirectory payjoin endpoint with the pubkey as identifying subdirectory. After enrollment, they await a payjoin request on a session identified by the subdirectory. 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 ohttp= parameter including the payjoin directory's [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration|OHTTP Key Configuration]].
 
 The sender constructs an encrypted and authenticated payload containing a PSBT and optional parameters similar to BIP 78. The resulting ciphertext ensures message secrecy and integrity when passed to the recipient by the subdirectory pj= endpoint.
 
@@ -102,9 +102,11 @@ The Payjoin PSBT MUST NOT:
 
 ====Enroll Messaging====
 
-The client discovers the OHTTP gateway's key configuration via an HTTP OPTIONS request to the gateway's URI.
+Receivers must enroll with a directory to a subdirectory allocated. 
 
-Receivers must enroll to have resources allocated on a directory. Sessions may begin by having a receiver send the static pubkey to the directory. The receiver returns the subdirectory endpoint url with the final subdirectory as base64-uri encoded pubkey AND an Oblivious HTTP Key Configuration. Enrollment may be replayed in case the receiver goes offline.
+A receiver must first discover the directory's OHTTP gateway key configuration via an authenticated bootstrap mechanism before it can enroll 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.
+
+Payjoin sessions begin by having a receiver send the static pubkey to the directory via OHTTP, receiving their subdirectory in a base64-uri encoded directory url as response. Enrollment may be replayed in case the receiver goes offline and should result in the same response.
 
 Optionally, before returning the uri the receiver may request an authentication token by presenting a message containing only the word Authenticate:  after which the receiver is required to submit an Authenticate:  including the token from the directory out of band. If authentication fails an error is returned.
 
@@ -144,10 +146,9 @@ A major benefit of BIP 78 payjoin over other coordination mechanisms is its comp
 
 This proposal defines the following new [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki|BIP 21 URI]] parameters:
 
+- ohttp represents the OHTTP Key Configuration of the directory server. This is a base64url encoded public key of the directory server's OHTTP Gateway. This parameter is required for version 2 payjoin URIs.
 - exp: represents a request expiration 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.
 
-BIP 78's BIP 21 payjoin parameters are also valid for version 2.
-
 ===Optional sender parameters===
 
 When the payjoin sender posts the original PSBT to the receiver, it can optionally specify the following HTTP query string parameters:
@@ -172,7 +173,7 @@ HTTP is ubiquitous. Using simple HTTP polling allows even Bitcoin Core to consid
 
 OHTTP protects sender and receiver IP addresses from both one another and from the directory. This makes it more difficult for a directory to correlate many payjoin transactions with a specific IP addresses by intersection.
 
-OHTTP relays can be run as basic HTTP proxies from wallet providers. Getting OHTTP Gateway configurations does require additional communication between each client and the directory, but this can be done over Tor (hidden service even), a VPN, or provided by a trusted third party like the wallet provider.
+OHTTP relays can be run as basic HTTP proxies from wallet providers or third parties.
 
 ===Message Padding===
 
@@ -194,7 +195,7 @@ This authenticated encryption with additional data [[https://en.wikipedia.org/wi
 
 ====HKDF-SHA256====
 
-SHA-256 is secure and widely available in bitcoin contexts.
+SHA-256 is considered secure and is necessarily available in bitcoin contexts.
 
 ===PSBT Version 2===
 
@@ -210,7 +211,7 @@ Since the Original PSBT is valid, even where exp= is specified, the
 
 ===Network privacy=== 
 
-Oblivious HTTP must be used to protect the IP address of both sender and receiver from the directory. This requires an additional key configuration to be shared in the bip21 URI and for the directory to support Oblivious HTTP. A secp256k1 HPKE OHTTP configuration should be used to leverage the crypto already in use for the payjoin protocol.
+Oblivious HTTP must be used to protect the IP address of both sender and receiver from the directory. This requires an additional key configuration to be shared in the bip21 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, not their peer's. Directories may aditionally be made available via Tor hidden service to allow either of the peers to protect their IP from the directory with without OHTTP.
 
@@ -224,7 +225,7 @@ Receivers may choose to support version 1 payloads. Version 2 payjoin URIs shoul
 
 ==Reference implementation==
 
-An production reference implementation client can be found at https://crates.io/crates/payjoin-cli/0.0.2-alpha. Source code for the clients, directory server, 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 implements an asynchronous payment flow using HTTP using PSBTv1 with encryption and Oblivious HTTP and may be configured to the following independent production relays:
+An production reference implementation client can be found at https://crates.io/crates/payjoin-cli. Source code for the clients, directory server, 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 implements an asynchronous payment flow using HTTP using PSBTv1 with encryption and Oblivious HTTP and may be configured to the following independent production relays:
 
 A payjoin directory server is run by the Payjoin Dev Kit team on https://payjo.in.
 

From 80b8bacfd02152ac7961090b6c74b38a6fd962d2 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Wed, 6 Mar 2024 11:19:01 -0500
Subject: [PATCH 09/50] Fix punctuation

---
 bip-0077.mediawiki | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index b7b098cd66..7d24816d18 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -213,7 +213,7 @@ Since the Original PSBT is valid, even where exp= is specified, the
 
 Oblivious HTTP must be used to protect the IP address of both sender and receiver from the directory. This requires an additional key configuration to be shared in the bip21 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, not their peer's. Directories may aditionally be made available via Tor hidden service to allow either of the peers to protect their IP from the directory with without OHTTP.
+Unlike BIP 78 implementations, sender and receiver peers will only see the IP address of the directory, not their peers. Directories may aditionally be made available via Tor hidden service to allow either of the peers to protect their IP from the directory with without OHTTP.
 
 ==Backwards compatibility==
 

From b5353b59b07b694c21ca5ef977e4453ea23d7375 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Wed, 6 Mar 2024 11:27:28 -0500
Subject: [PATCH 10/50] Make base64URL references consistent

---
 bip-0077.mediawiki | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 7d24816d18..2dcd73ad9d 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -63,7 +63,7 @@ Payjoin v2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.m
 The payjoin version 2 protocol takes the following steps:
 
 - The recipient sends their payjoin pubkey and optional authentication credential according to [[#directory-enrollment|receiver directory enrollment]] protocol to receive a subdirectory allocation. It may go offline and replay enrollment to come back online.
-- Out of band, the receiver of the payment, shares a bitcoin URI with the sender including a pj= query parameter including the subdirectory as a base64-uri encoded pubkey. 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. An ohttp= parameter containing the directory's base64-url Key Config should also be provided.
+- Out of band, the receiver of the payment, shares a bitcoin URI with the sender including a pj= query parameter including the subdirectory as a base64URL encoded pubkey. 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. An ohttp= parameter containing the directory's base64URL Key Config should also be provided.
 - The sender creates a valid version 2 PSBT satisfying the [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. We call this the Original PSBT. This Original PSBT, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#original-psbt-request|Original PSBT Request]] is sent to the directory's OHTTP Gateway.
 - The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry.
 - The request is stored in the subdirectory.
@@ -106,7 +106,7 @@ Receivers must enroll with a directory to a subdirectory allocated.
 
 A receiver must first discover the directory's OHTTP gateway key configuration via an authenticated bootstrap mechanism before it can enroll 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.
 
-Payjoin sessions begin by having a receiver send the static pubkey to the directory via OHTTP, receiving their subdirectory in a base64-uri encoded directory url as response. Enrollment may be replayed in case the receiver goes offline and should result in the same response.
+Payjoin sessions begin by having a receiver send the static pubkey to the directory via OHTTP, receiving their subdirectory in a base64URL encoded directory url as response. Enrollment may be replayed in case the receiver goes offline and should result in the same response.
 
 Optionally, before returning the uri the receiver may request an authentication token by presenting a message containing only the word Authenticate:  after which the receiver is required to submit an Authenticate:  including the token from the directory out of band. If authentication fails an error is returned.
 
@@ -114,7 +114,7 @@ In the case a directory is operated by an exchange, it may give out authenticati
 
 ====Send Messaging====
 
-The version 2 Original PSBT is placed in an HTTP POST request body, base64 serialized, with text/plain in the Content-Type HTTP header and Content-Length set correctly, as in version 1, before being encoded into BHTTP and encrypted according to the HPKE protocol. This Original PSBT BHTTP Request is then encrypted according to the HPKE, generating an ephemeral keypair `e` from which it derives a shared secret `es` with the receiver's key `s`. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Original PSBT BHTTP Request and serialized ephemeral key `e`'s pubkey as associated data using ChaCha20Poly1305. A payload is constructed by concatenating the ephemeral pubkey, the nonce, and the ciphertext. This payload is then sent to the directory in an OHTTP request encapsulating the binary payload.
+The version 2 Original PSBT is placed in an HTTP POST request body as binary before being encoded into BHTTP and encrypted according to the HPKE protocol. This Original PSBT BHTTP Request is then encrypted according to the HPKE, generating an ephemeral keypair `e` from which it derives a shared secret `es` with the receiver's key `s`. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Original PSBT BHTTP Request and serialized ephemeral key `e`'s pubkey as associated data using ChaCha20Poly1305. A payload is constructed by concatenating the ephemeral pubkey, the nonce, and the ciphertext. This payload is then sent to the directory in an OHTTP request encapsulating the binary payload.
 
 The directory's OHTTP Gateway decapsulates the OHTTP request, decrypts the payload, and forwards the BHTTP POST request to the receiver's internal subdirectory endpoint which stores the HPKE encrypted payload to be forwarded to the receiver. The directory's OHTTP Gateway then awaits a response from the receiver's subdirectory endpoint, encapsulates it, and responds according to OHTTP.
 
@@ -146,7 +146,7 @@ A major benefit of BIP 78 payjoin over other coordination mechanisms is its comp
 
 This proposal defines the following new [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki|BIP 21 URI]] parameters:
 
-- ohttp represents the OHTTP Key Configuration of the directory server. This is a base64url encoded public key of the directory server's OHTTP Gateway. This parameter is required for version 2 payjoin URIs.
+- ohttp represents the OHTTP Key Configuration of the directory server. This is a base64URL encoded public key of the directory server's OHTTP Gateway. This parameter is required for version 2 payjoin URIs.
 - exp: represents a request expiration 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.
 
 ===Optional sender parameters===
@@ -183,7 +183,7 @@ All cyphertexts should be padded to the same length of 7168 bytes to prevent tra
 
 Hybrid Public Key Encryption 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 v2 appication 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/NKpsk0/|IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static keys shared in URIs must only for a single session. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5|base64url]] encoding as a subdirectory of the directory server in the pj= parameter.
+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/NKpsk0/|IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static keys shared in URIs must only for a single session. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5|base64URL]] encoding as a subdirectory of the directory server in the pj= parameter.
 
 ====Secp256k1====
 

From 9e8b4d7ee755bb72a0389a3bce44731d131ecad1 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Wed, 6 Mar 2024 11:29:42 -0500
Subject: [PATCH 11/50] Reference standardized Secp256k1 DHKEM for HPKE

---
 bip-0077.mediawiki | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 2dcd73ad9d..ffd30a5be2 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -185,9 +185,9 @@ Hybrid Public Key Encryption is a modern web standard for secure message exchang
 
 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/NKpsk0/|IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static keys shared in URIs must only for a single session. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5|base64URL]] encoding as a subdirectory of the directory server in the pj= parameter.
 
-====Secp256k1====
+====Secp256k1-based DHKEM====
 
-Secp256k1 should be used in place of HPKE's specified DH functions because of it's availability in bitcoin contexts. A proposal to standardize its inclusion may be appropriate.
+[[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====
 

From 3c1629bb2361aa229adbde36527b7e1bc59138dc Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Tue, 26 Mar 2024 23:45:48 -0400
Subject: [PATCH 12/50] Add Comments-URI

---
 bip-0077.mediawiki | 1 +
 1 file changed, 1 insertion(+)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index ffd30a5be2..eb82665732 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -3,6 +3,7 @@
   Layer: Applications
   Title: Payjoin Version 2: Serverless Payjoin
   Author: Dan Gould 
+  Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0077
   Status: Draft
   Replaces: 78
   Type: Standards Track

From a0d365447129ffa31aca98ef84f54eaf6641b08d Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Thu, 2 May 2024 22:59:22 -0400
Subject: [PATCH 13/50] fixup: Format and spell check

Co-authored-by: spacebear <144076611+grizznaut@users.noreply.github.com>
---
 bip-0077.mediawiki | 67 +++++++++++++++++++++++-----------------------
 1 file changed, 33 insertions(+), 34 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index eb82665732..52ca07d3f8 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -5,7 +5,6 @@
   Author: Dan Gould 
   Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0077
   Status: Draft
-  Replaces: 78
   Type: Standards Track
   Created: 2023-08-08
   License: BSD-2-Clause
@@ -23,7 +22,7 @@ This BIP is licensed under the 2-clause BSD license.
 
 Payjoin 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." Breaking that common-input ownership assumption and others requires input from multiple owners. Cooperative transaction construction also increases transaction throughput by providing new opportunity for payment batching and transaction cut-through.
 
-Version 1 coordinates payjoins over a public server endpoint secured by either TLS or Tor hidden service hosted by the receiver. Version 1 is synchronous, requiring both sender and reciever 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 develoepers [[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-January/018358.html|regard]] these as limits to payjoin 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 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 adaptable to a majority of wallet environments. This is realized as a simple protocol built on bitcoin URI requests, web standards, common crypto, and minimal dependencies.
 
@@ -31,7 +30,7 @@ The primary goal of this proposal is to provide a practical coordination mechani
 
 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. This protocol also upgrades to PSBT version 2 to simplify transaction construction.
 
-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 Payjoin PSBT in flight, thus requiring payment output substitition to be disabled. Output substitition 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 substition while using a directory relay without compromising sender or receiver privacy.
+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 Payjoin 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 while using a directory relay 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 stealing funds.
 
@@ -39,13 +38,13 @@ The protocols in this document reuse BIP 78's BIP 21 URI parameters. A Original
 
 ===Relation to Stowaway===
 
-[[https://code.samourai.io/wallet/ExtLibJ/-/blob/develop/doc/cahoots/STOWAWAY.md|Stowaway]] is a payjoin coordination mechanism which depends on Tor, a third-party relay, and the [[https://samouraiwallet.com/paynym|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.
+[[https://code.samourai.io/wallet/ExtLibJ/-/blob/develop/doc/cahoots/STOWAWAY.md|Stowaway]] is a payjoin coordination mechanism which depends on Tor, a third-party relay, and the [[https://samouraiwallet.com/paynym|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 enroll with a store-and-forward directory server to receive payjoin. 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 a application layer authenticated encryption and relayed asynchronus networking, the version 2 messaging takes much the same form as the existing BIP 78 specification.
+Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP endpoint, this scheme allows an HTTP client to enroll with a store-and-forward directory server to receive payjoin. 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 a application layer authenticated encryption and relayed asynchronous networking, the version 2 messaging takes much the same form as the existing BIP 78 specification.
 
 ===Basic scheme===
 
@@ -63,47 +62,47 @@ Payjoin v2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.m
 
 The payjoin version 2 protocol takes the following steps:
 
-- The recipient sends their payjoin pubkey and optional authentication credential according to [[#directory-enrollment|receiver directory enrollment]] protocol to receive a subdirectory allocation. It may go offline and replay enrollment to come back online.
-- Out of band, the receiver of the payment, shares a bitcoin URI with the sender including a pj= query parameter including the subdirectory as a base64URL encoded pubkey. 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. An ohttp= parameter containing the directory's base64URL Key Config should also be provided.
-- The sender creates a valid version 2 PSBT satisfying the [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. We call this the Original PSBT. This Original PSBT, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#original-psbt-request|Original PSBT Request]] is sent to the directory's OHTTP Gateway.
-- The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry.
-- The request is stored in the subdirectory.
-- Once the receiver is online, it sends /receiverequests to await updates from the subdirectory. The receiver decrypts and authenticates the response which it checks according to [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. It updates the Original PSBT to include new signed inputs and outputs, invalidating sender signatures, and may adjust the fee. The result is called the Payjoin PSBT.
-- The Payjoin PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and sent to the directory's OHTTP Gateway.
-- The directory awaits a request from the sender if it goes offline. Upon request, it relays the encrypted Payjoin PSBT.
-- The sender validates the Payjoin PSBT according to [[#senders-payjoin-psbt-checklist|the sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network.
+* The recipient sends their payjoin pubkey and optional authentication credential according to [[#directory-enrollment|receiver directory enrollment]] protocol to receive a subdirectory allocation. It may go offline and replay enrollment to come back online.
+* Out of band, the receiver of the payment, shares a bitcoin URI with the sender including a pj= query parameter including the subdirectory as a base64URL encoded pubkey. 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. An ohttp= parameter containing the directory's base64URL Key Config should also be provided.
+* The sender creates a valid version 2 PSBT satisfying the [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. We call this the Original PSBT. This Original PSBT, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#original-psbt-request|Original PSBT Request]] is sent to the directory's OHTTP Gateway.
+* The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry.
+* The request is stored in the subdirectory.
+* Once the receiver is online, it sends /receiverequests to await updates from the subdirectory. The receiver decrypts and authenticates the response which it checks according to [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. It updates the Original PSBT to include new signed inputs and outputs, invalidating sender signatures, and may adjust the fee. The result is called the Payjoin PSBT.
+* The Payjoin PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and sent to the directory's OHTTP Gateway.
+* The directory awaits a request from the sender if it goes offline. Upon request, it relays the encrypted Payjoin PSBT.
+* The sender validates the Payjoin PSBT according to [[#senders-payjoin-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. 
-- Set input and output Transaction Modifiable Flags to 1
-- Be broadcastable.
+* Include complete UTXO data.
+* Be signed.
+* Exclude unnecessary fields such as global xpubs or keypath information. 
+* Set input and output Transaction Modifiable Flags to 1
+* Be broadcastable.
 
 The Original PSBT MAY:
 
-- Include outputs unrelated to the sender-receiver transfer for batching purposes.
-- Set SIGHASH_SINGLE Transaction Modifiable Flags flags to 1
+* Include outputs unrelated to the sender-receiver transfer for batching purposes.
+* Set SIGHASH_SINGLE Transaction Modifiable Flags flags to 1
 
 The Payjoin 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.
+* 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 Payjoin PSBT sender MAY:
 
-- Add, remove or modify Original PSBT outputs under the control of the receiver (i.e. not sender change).
+* Add, remove or modify Original PSBT outputs under the control of the receiver (i.e. not sender change).
 
 The Payjoin 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 transaction.
+* 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 transaction.
 
 ====Enroll Messaging====
 
-Receivers must enroll with a directory to a subdirectory allocated. 
+Receivers must enroll with a directory to have a subdirectory allocated to them as follows.
 
 A receiver must first discover the directory's OHTTP gateway key configuration via an authenticated bootstrap mechanism before it can enroll 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.
 
@@ -147,14 +146,14 @@ A major benefit of BIP 78 payjoin over other coordination mechanisms is its comp
 
 This proposal defines the following new [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki|BIP 21 URI]] parameters:
 
-- ohttp represents the OHTTP Key Configuration of the directory server. This is a base64URL encoded public key of the directory server's OHTTP Gateway. This parameter is required for version 2 payjoin URIs.
-- exp: represents a request expiration 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.
+* ohttp represents the OHTTP Key Configuration of the directory server. This is a base64URL encoded public key of the directory server's OHTTP Gateway. This parameter is required for version 2 payjoin URIs.
+* exp: represents a request expiration 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.
 
 ===Optional sender parameters===
 
 When the payjoin sender posts the original PSBT to the receiver, it can optionally 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.
+* 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.
 
@@ -182,7 +181,7 @@ All cyphertexts should be padded to the same length of 7168 bytes to prevent tra
 
 ===Secp256k1 Hybrid Public Key Encryption===
 
-Hybrid Public Key Encryption 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 v2 appication specific configuration to use DHKEM(Secp256k1, HKDF-SHA256) and ChaCha20Poly1305 AEAD.
+Hybrid Public Key Encryption 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 v2 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/NKpsk0/|IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static keys shared in URIs must only for a single session. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5|base64URL]] encoding as a subdirectory of the directory server in the pj= parameter.
 
@@ -210,11 +209,11 @@ Since we make use of 0-RTT HPKE, the first message containing the sender's origi
 
 Since the Original PSBT is valid, even where exp= is specified, the receiver may broadcast it and lose out on savings from payment batching and  privacy protection from payjoin structure at any time. Though unfortunate, this failure mode is the typical bitcoin transaction flow today anyhow.
 
-===Network privacy=== 
+===Network privacy===
 
 Oblivious HTTP must be used to protect the IP address of both sender and receiver from the directory. This requires an additional key configuration to be shared in the bip21 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, not their peers. Directories may aditionally be made available via Tor hidden service to allow either of the peers to protect their IP from the directory with without OHTTP.
+Unlike BIP 78 implementations, sender and receiver peers will only see the IP address of the directory, not their peers. Directories may additionally be made available via Tor hidden service to allow either of the peers to protect their IP from the directory with without OHTTP.
 
 ==Backwards compatibility==
 

From b758311ba6fd4d01cc384b040d12a1c26b4f5497 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Thu, 2 May 2024 23:08:04 -0400
Subject: [PATCH 14/50] Add BIP 77 to README

---
 README.mediawiki | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/README.mediawiki b/README.mediawiki
index 94ecb8bcb3..1801ebcdb1 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: Serverless Payjoin
+| Dan Gould
+| Standard
+| Draft
+|-
 | [[bip-0078.mediawiki|78]]
 | Applications
 | A Simple Payjoin Proposal

From 95a3b14b817f57461f05e9a0b413d3a3f92d0279 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Fri, 3 May 2024 16:49:31 -0400
Subject: [PATCH 15/50] Add Payjoin V2 overview diagram

---
 bip-0077.mediawiki | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 52ca07d3f8..74382869de 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -56,6 +56,48 @@ The sender constructs an encrypted and authenticated payload containing a PSBT a
 
 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====
+
+
++----------+                 +-----------+       +--------+  +---------+
+| Receiver |                 | Directory |       | Sender |  | Network |
++----------+                 +-----------+       +--------+  +---------+
+|                                  |                  |                |
+| Request subdirectory             |                  |                |
++--------------------------------->|                  |                |
+|                                  |                  |                |
+|           subdirectory           |                  |                |
+|<---------------------------------|                  |                |
+|                                  |                  |                |
+|      destination (address,       |                  |                |
+|        subdirectory)             |                  |                |
++---------------------------------------------------->|                |
+|                                  |                  |                |
+|      Request Original PSBT       |                  |                |
++- - - - - - - - - - - - - - - - ->|                  |                |
+|                                  |  Original PSBT   |                |
+|                                  |<- - - - - - - - -|                |
+|                                  |                  |                |
+|                                  |                  |                |
+|          Original PSBT           |                  |                |
+|<---------------------------------|                  |                |
+|                                  |                  |                |
+|                                  |                  |                |
+|             Payjoin PSBT         |                  |                |
++--------------------------------->|                  |                |
+|                                  |   Payjoin PSBT   |                |
+|                                  |----------------->|                |
+|                                  |                  |                |
+|                                  |                  |   Payjoin      |
+|                                  |                  +--------------->|
+|                                  |                  |                |
++                                  +                  +                +
+
+Key: 
+|-----> Single transmission
+|- - -> Polled transmission
+
+ ===Payjoin version 2 messaging=== Payjoin v2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki|BIP 370 PSBT v2]] format to fascilitate PSBT mutation. From 6646e9908c7e7dd14426582be63a341519c35d50 Mon Sep 17 00:00:00 2001 From: DanGould Date: Sun, 5 May 2024 20:58:24 -0400 Subject: [PATCH 16/50] Add Oblivious HTTP Sequence Diagram --- bip-0077.mediawiki | 5 +++++ bip-0077/oblivious-http-sequence.png | Bin 0 -> 57987 bytes 2 files changed, 5 insertions(+) create mode 100644 bip-0077/oblivious-http-sequence.png diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index 74382869de..66a402e3e8 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -217,6 +217,11 @@ OHTTP protects sender and receiver IP addresses from both one another and from t OHTTP relays can be run as basic HTTP proxies from wallet providers or third parties. +====OHTTP Sequence Diagram==== + + + + ===Message Padding=== All cyphertexts should be padded to the same length of 7168 bytes to prevent traffic analysis. This is sufficient size for most transaction PSBTs without exceeding the 8KB limit of many HTTP/1.1 web servers. diff --git a/bip-0077/oblivious-http-sequence.png b/bip-0077/oblivious-http-sequence.png new file mode 100644 index 0000000000000000000000000000000000000000..53809d7f17470e827ff4fcb1e5ca160d08a0fa47 GIT binary patch literal 57987 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 literal 0 HcmV?d00001 From 5ff5b7ae776ae8e9e160ced98dce1ab10e9019df Mon Sep 17 00:00:00 2001 From: DanGould Date: Mon, 6 May 2024 17:59:46 -0400 Subject: [PATCH 17/50] Correct links and spelling Co-authored-by: thebrandonlucas <38222767+thebrandonlucas@users.noreply.github.com> --- bip-0077.mediawiki | 54 +++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index 66a402e3e8..a7cc09300a 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -12,7 +12,7 @@ ==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 them to host a secure public endpoint. This requirement is replaced with an untrusted third-party directory and HTTP clients which 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. +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 them to host a secure public endpoint. This requirement is replaced with an untrusted third-party directory and HTTP clients which 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== @@ -22,15 +22,15 @@ This BIP is licensed under the 2-clause BSD license. Payjoin 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." Breaking that common-input ownership assumption and others requires input from multiple owners. Cooperative transaction construction also increases transaction throughput by providing new opportunity for payment batching and transaction cut-through. -Version 1 coordinates payjoins over a public server endpoint secured by either TLS or Tor hidden service hosted by the receiver. Version 1 is 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. +Version 1 coordinates payjoins over a public server endpoint secured by either TLS or Tor hidden service hosted by the receiver. Version 1 is 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 adaptable to a majority of wallet environments. This is realized as a simple protocol built on bitcoin URI requests, web standards, common crypto, 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. This protocol also upgrades to PSBT version 2 to simplify transaction construction. +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. This protocol also upgrades to PSBT version 2 to simplify transaction construction. -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 Payjoin 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 while using a directory relay without compromising sender or receiver privacy. +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 Payjoin 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 while using a directory relay 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 stealing funds. @@ -38,23 +38,23 @@ The protocols in this document reuse BIP 78's BIP 21 URI parameters. A Original ===Relation to Stowaway=== -[[https://code.samourai.io/wallet/ExtLibJ/-/blob/develop/doc/cahoots/STOWAWAY.md|Stowaway]] is a payjoin coordination mechanism which depends on Tor, a third-party relay, and the [[https://samouraiwallet.com/paynym|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. +[[https://code.samourai.io/wallet/ExtLibJ/-/blob/develop/doc/cahoots/STOWAWAY.md Stowaway]] is a payjoin coordination mechanism which depends on Tor, a third-party relay, and the [[https://samouraiwallet.com/paynym 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 enroll with a store-and-forward directory server to receive payjoin. 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 a application layer authenticated encryption and relayed asynchronous networking, the version 2 messaging takes much the same form as the existing BIP 78 specification. +Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP endpoint, this scheme allows an HTTP client to enroll with a store-and-forward directory server to receive payjoin. 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, they start a session to receive messages and allocate a subdirectory from which to relay messages. The first message must include their pubkey to be enrolled as a subdirectory identifier. The next message from the directory to sender includes the enrolled subdirectory payjoin endpoint with the pubkey as identifying subdirectory. After enrollment, they await a payjoin request on a session identified by the subdirectory. 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 ohttp= parameter including the payjoin directory's [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration|OHTTP Key Configuration]]. +Rather than hosting a public server, they start a session to receive messages and allocate a subdirectory from which to relay messages. The first message must include their pubkey to be enrolled as a subdirectory identifier. The next message from the directory to sender includes the enrolled subdirectory payjoin endpoint with the pubkey as identifying subdirectory. After enrollment, they await a payjoin request on a session identified by the subdirectory. 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 ohttp= parameter including the payjoin directory's [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration OHTTP Key Configuration]]. The sender constructs an encrypted and authenticated payload containing a PSBT and optional parameters similar to BIP 78. The resulting ciphertext ensures message secrecy and integrity when passed to the recipient 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. +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==== @@ -100,16 +100,16 @@ Key: ===Payjoin version 2 messaging=== -Payjoin v2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki|BIP 370 PSBT v2]] format to fascilitate PSBT mutation. +Payjoin v2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki BIP 370 PSBT v2]] format to facilitate PSBT mutation. The payjoin version 2 protocol takes the following steps: -* The recipient sends their payjoin pubkey and optional authentication credential according to [[#directory-enrollment|receiver directory enrollment]] protocol to receive a subdirectory allocation. It may go offline and replay enrollment to come back online. +* The recipient sends their payjoin pubkey and optional authentication credential according to the [[#enroll-messaging|enroll messaging]] protocol to receive a subdirectory allocation. It may go offline and replay enrollment to come back online. * Out of band, the receiver of the payment, shares a bitcoin URI with the sender including a pj= query parameter including the subdirectory as a base64URL encoded pubkey. 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. An ohttp= parameter containing the directory's base64URL Key Config should also be provided. -* The sender creates a valid version 2 PSBT satisfying the [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. We call this the Original PSBT. This Original PSBT, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#original-psbt-request|Original PSBT Request]] is sent to the directory's OHTTP Gateway. +* The sender creates a valid version 2 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, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#send-messaging|Original PSBT Request send message]] is sent to the directory's OHTTP Gateway. * The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry. * The request is stored in the subdirectory. -* Once the receiver is online, it sends /receiverequests to await updates from the subdirectory. The receiver decrypts and authenticates the response which it checks according to [[https://github.com/bitcoin/bips/blob/master/bip-0078#receivers-original-psbt-checklist|the receiver checklist]]. It updates the Original PSBT to include new signed inputs and outputs, invalidating sender signatures, and may adjust the fee. The result is called the Payjoin PSBT. +* Once the receiver is online, it sends /receiverequests to await updates from 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]]. It updates the Original PSBT to include new signed inputs and outputs, invalidating sender signatures, and may adjust the fee. The result is called the Payjoin PSBT. * The Payjoin PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and sent to the directory's OHTTP Gateway. * The directory awaits a request from the sender if it goes offline. Upon request, it relays the encrypted Payjoin PSBT. * The sender validates the Payjoin PSBT according to [[#senders-payjoin-psbt-checklist|the sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network. @@ -140,13 +140,13 @@ The Payjoin PSBT sender MAY: The Payjoin 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 transaction. +* Decrease the absolute fee of the original PSBT. ====Enroll Messaging==== Receivers must enroll with a directory to have a subdirectory allocated to them as follows. -A receiver must first discover the directory's OHTTP gateway key configuration via an authenticated bootstrap mechanism before it can enroll 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. +A receiver must first discover the directory's OHTTP gateway key configuration via an authenticated bootstrap mechanism before it can enroll 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. Payjoin sessions begin by having a receiver send the static pubkey to the directory via OHTTP, receiving their subdirectory in a base64URL encoded directory url as response. Enrollment may be replayed in case the receiver goes offline and should result in the same response. @@ -168,27 +168,27 @@ Once an Original PSBT Payload is decrypted and checked according to the list, th ===Receiver's Payjoin PSBT checklist=== -Other than requiring PSBTv2 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]] +Other than requiring PSBTv2 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]] ===Sender's Payjoin PSBT checklist=== -The version 2 sender's checklist is largely the same as the [[https://github.com/bitcoin/bips/blob/master/bip-0078#senders-payjoin-proposal-checklist|the BIP 78 checklist]] with the exception that 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 headaches since it required the sender to add them back to the Payjoin proposal PSBT. Version 2 has no such requirement. +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 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 headaches since 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. It stores Payjoin payloads to support asynchronous communication. It must only accept OHTTP requests with an OHTTP Gateway for Payjoin version 2, accepting encrypted payloads. It may optionally accept HTTP/1.1 POST requests without HTTP to enrolled subdirectories to support backwards compatible Payjoin version 1 requests. +The payjoin directory provides a rendezvous point for sender and receiver to meet. It stores Payjoin payloads to support asynchronous communication. It must only accept OHTTP requests with an OHTTP Gateway for Payjoin version 2, accepting encrypted payloads. It may optionally accept HTTP/1.1 POST requests without HTTP to enrolled subdirectories to support backwards compatible Payjoin version 1 requests. ===Subdirectories=== -Each receiver subdirectory on the directory server has a buffer for requests and one for responses. Each buffer updates listeners through awaitable events so that updates are immediately apparent upon client request. +Each receiver subdirectory allocated on the directory has a buffer for requests and one for responses. Each buffer updates listeners through awaitable events so that updates are immediately apparent upon client request. ===BIP 21 receiver parameters=== A major benefit of BIP 78 payjoin over other coordination mechanisms is its compatibility with the universal BIP 21 bitcoin URI standard. -This proposal defines the following new [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki|BIP 21 URI]] parameters: +This proposal defines the following new [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki BIP 21 URI]] parameters: -* ohttp represents the OHTTP Key Configuration of the directory server. This is a base64URL encoded public key of the directory server's OHTTP Gateway. This parameter is required for version 2 payjoin URIs. +* ohttp represents the OHTTP Key Configuration of the directory. This is a base64URL encoded public key of the directory's OHTTP Gateway. This parameter is required for version 2 payjoin URIs. * exp: represents a request expiration 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. ===Optional sender parameters=== @@ -230,15 +230,15 @@ All cyphertexts should be padded to the same length of 7168 bytes to prevent tra Hybrid Public Key Encryption 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 v2 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/NKpsk0/|IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static keys shared in URIs must only for a single session. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5|base64URL]] encoding as a subdirectory of the directory server in the pj= parameter. +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/NKpsk0/ IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static keys shared in URIs must only for a single 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. +[[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 seems to be making its way into bitcoin by way of [[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. +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 seems to be making its way into bitcoin by way of [[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==== @@ -260,11 +260,11 @@ Since the Original PSBT is valid, even where exp= is specified, the Oblivious HTTP must be used to protect the IP address of both sender and receiver from the directory. This requires an additional key configuration to be shared in the bip21 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, not their peers. Directories may additionally be made available via Tor hidden service to allow either of the peers to protect their IP from the directory with without OHTTP. +Unlike BIP 78 implementations, sender and receiver peers will only see the IP address of the directory, not their peers. Directories may additionally be made available via Tor hidden service 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|BIP21's URI Scheme]]. +The receivers advertise payjoin capabilities through [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki BIP21's URI Scheme]]. Senders not supporting payjoin will just ignore the pj= parameter and proceed to typical address-based transaction flows. req-pj= may be used to compel payjoin. @@ -272,9 +272,9 @@ Receivers may choose to support version 1 payloads. Version 2 payjoin URIs shoul ==Reference implementation== -An production reference implementation client can be found at https://crates.io/crates/payjoin-cli. Source code for the clients, directory server, 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 implements an asynchronous payment flow using HTTP using PSBTv1 with encryption and Oblivious HTTP and may be configured to the following independent production relays: +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 implements an asynchronous payment flow using HTTP using PSBTv1 with encryption and Oblivious HTTP and may be configured to the following independent production relays: -A payjoin directory server is run by the Payjoin Dev Kit team on https://payjo.in. +A payjoin directory is run by the Payjoin Dev Kit team on https://payjo.in. Independent Oblivious HTTP relays are run by Obscura VPN at https://ohttp-relay.obscuravpn.io/payjoin and by BOB Spaces at https://pj.bobspacebkk.com. From ce66047deddee3d53c648c4947832ccfb7244475 Mon Sep 17 00:00:00 2001 From: DanGould Date: Tue, 7 May 2024 16:23:29 -0400 Subject: [PATCH 18/50] Wrap blocks --- bip-0077.mediawiki | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index a7cc09300a..41fdf30e18 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -109,7 +109,7 @@ The payjoin version 2 protocol takes the following steps: * The sender creates a valid version 2 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, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#send-messaging|Original PSBT Request send message]] is sent to the directory's OHTTP Gateway. * The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry. * The request is stored in the subdirectory. -* Once the receiver is online, it sends /receiverequests to await updates from 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]]. It updates the Original PSBT to include new signed inputs and outputs, invalidating sender signatures, and may adjust the fee. The result is called the Payjoin PSBT. +* Once the receiver is online, it sends /receive requests to await updates from 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]]. It updates the Original PSBT to include new signed inputs and outputs, invalidating sender signatures, and may adjust the fee. The result is called the Payjoin PSBT. * The Payjoin PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and sent to the directory's OHTTP Gateway. * The directory awaits a request from the sender if it goes offline. Upon request, it relays the encrypted Payjoin PSBT. * The sender validates the Payjoin PSBT according to [[#senders-payjoin-psbt-checklist|the sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network. @@ -156,15 +156,15 @@ In the case a directory is operated by an exchange, it may give out authenticati ====Send Messaging==== -The version 2 Original PSBT is placed in an HTTP POST request body as binary before being encoded into BHTTP and encrypted according to the HPKE protocol. This Original PSBT BHTTP Request is then encrypted according to the HPKE, generating an ephemeral keypair `e` from which it derives a shared secret `es` with the receiver's key `s`. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Original PSBT BHTTP Request and serialized ephemeral key `e`'s pubkey as associated data using ChaCha20Poly1305. A payload is constructed by concatenating the ephemeral pubkey, the nonce, and the ciphertext. This payload is then sent to the directory in an OHTTP request encapsulating the binary payload. +The version 2 Original PSBT is placed in an HTTP POST request body as binary before being encoded into BHTTP and encrypted according to the HPKE protocol. This Original PSBT BHTTP Request is then encrypted according to the HPKE, generating an ephemeral keypair e from which it derives a shared secret es with the receiver's key s. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Original PSBT BHTTP Request and serialized ephemeral key e's pubkey as associated data using ChaCha20Poly1305. A payload is constructed by concatenating the ephemeral pubkey, the nonce, and the ciphertext. This payload is then sent to the directory in an OHTTP request encapsulating the binary payload. The directory's OHTTP Gateway decapsulates the OHTTP request, decrypts the payload, and forwards the BHTTP POST request to the receiver's internal subdirectory endpoint which stores the HPKE encrypted payload to be forwarded to the receiver. The directory's OHTTP Gateway then awaits a response from the receiver's subdirectory endpoint, encapsulates it, and responds according to OHTTP. ====Receive Messaging==== -The receiver sends a GET request to the path of the subdirectory followed by `/receive`. This request is encapsulated in OHTTP. It awaits an OHTTP response from the directory containing the BHTTP request from the sender with status code 200 OK, or sends a new OHTTP request after receiving 202 ACCEPTED notifying the receiver that the directory has not yet received an request from the sender. +The receiver sends a GET request to the path of the subdirectory followed by /receive. This request is encapsulated in OHTTP. It awaits an OHTTP response from the directory containing the BHTTP request from the sender with status code 200 OK, or sends a new OHTTP request after receiving 202 ACCEPTED notifying the receiver that the directory has not yet received an request from the sender. -Once an Original PSBT Payload is decrypted and checked according to the list, the receiver may respond with a Payjoin PSBT. The receiver encrypts the PSBT according to the HPKE protocol, generating an ephemeral keypair `e` from which it derives a shared secret `ee` with the sender's key `e` from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Payjoin PSBT and serialized receiver ephemeral key `e`'s pubkey as associated data using ChaCha20Poly1305. A payload is constructed by concatenating the ephemeral pubkey, the nonce, and the ciphertext. This payload is then sent to the directory in an OHTTP request encapsulating the binary payload as a POST message to the subdirectory followed by `/receive`. +Once an Original PSBT Payload is decrypted and checked according to the list, the receiver may respond with a Payjoin PSBT. The receiver encrypts the PSBT according to the HPKE protocol, generating an ephemeral keypair e from which it derives a shared secret ee with the sender's key e from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Payjoin PSBT and serialized receiver ephemeral key e's pubkey as associated data using ChaCha20Poly1305. A payload is constructed by concatenating the ephemeral pubkey, the nonce, and the ciphertext. This payload is then sent to the directory in an OHTTP request encapsulating the binary payload as a POST message to the subdirectory followed by /receive. ===Receiver's Payjoin PSBT checklist=== From 07db5536684b2c111f4bfa0e468d3a5ee1473c88 Mon Sep 17 00:00:00 2001 From: DanGould Date: Tue, 7 May 2024 16:25:21 -0400 Subject: [PATCH 19/50] Fix basic scheme actors --- bip-0077.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index 41fdf30e18..c36c48adc9 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -50,7 +50,7 @@ Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP e 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, they start a session to receive messages and allocate a subdirectory from which to relay messages. The first message must include their pubkey to be enrolled as a subdirectory identifier. The next message from the directory to sender includes the enrolled subdirectory payjoin endpoint with the pubkey as identifying subdirectory. After enrollment, they await a payjoin request on a session identified by the subdirectory. 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 ohttp= parameter including the payjoin directory's [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration OHTTP Key Configuration]]. +Rather than hosting a public server, they start a session to receive messages and allocate a subdirectory from which to relay messages. The first message must include their pubkey to be enrolled as a subdirectory identifier. The response message from the directory to receiver includes the newly enrolled subdirectory payjoin endpoint with the pubkey as identifying subdirectory. After enrollment, they await a payjoin request on a session identified by the subdirectory. 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 ohttp= parameter including the payjoin directory's [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration OHTTP Key Configuration]]. The sender constructs an encrypted and authenticated payload containing a PSBT and optional parameters similar to BIP 78. The resulting ciphertext ensures message secrecy and integrity when passed to the recipient by the subdirectory pj= endpoint. From b693fb9a2ee19175fdc9a9f42271c2eab1403086 Mon Sep 17 00:00:00 2001 From: DanGould Date: Tue, 7 May 2024 16:28:17 -0400 Subject: [PATCH 20/50] Fix dead samourai links --- bip-0077.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index c36c48adc9..d05e5718b5 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -38,7 +38,7 @@ The protocols in this document reuse BIP 78's BIP 21 URI parameters. A Original ===Relation to Stowaway=== -[[https://code.samourai.io/wallet/ExtLibJ/-/blob/develop/doc/cahoots/STOWAWAY.md Stowaway]] is a payjoin coordination mechanism which depends on Tor, a third-party relay, and the [[https://samouraiwallet.com/paynym 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. +[[https://docs.samourai.io/en/spend-tools#stowaway Stowaway]] was a payjoin coordination mechanism which depends 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== From f9b4b911eda4f0154ee2ffc85cf4037f57fd0ab3 Mon Sep 17 00:00:00 2001 From: DanGould Date: Fri, 10 May 2024 16:13:27 -0400 Subject: [PATCH 21/50] Orient motivation around a problem --- bip-0077.mediawiki | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index d05e5718b5..681a66f3fa 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -12,7 +12,7 @@ ==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 them to host a secure public endpoint. This requirement is replaced with an untrusted third-party directory and HTTP clients which 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. +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 which 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== @@ -20,11 +20,13 @@ This BIP is licensed under the 2-clause BSD license. ==Motivation== -Payjoin 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." Breaking that common-input ownership assumption and others requires input from multiple owners. Cooperative transaction construction also increases transaction throughput by providing new opportunity for payment batching and transaction cut-through. +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. -Version 1 coordinates payjoins over a public server endpoint secured by either TLS or Tor hidden service hosted by the receiver. Version 1 is 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 payjoin protocols automate cooperative transaction construction to break that common-input assumption. The increased the opportunity to batch payments and and execute transaction cut-through increases intent throughput, since multiple intents combined take up fewer bytes than independent transactions. -The primary goal of this proposal is to provide a practical coordination mechanism adaptable to a majority of wallet environments. This is realized as a simple protocol built on bitcoin URI requests, web standards, common crypto, and minimal dependencies. +Version 1's requirements have proven to be an obstacle to adoption. V1 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 viable to implement in a majority of bitcoin software environments. This is realized as a simple protocol built on bitcoin URI requests, web standards, common crypto, and minimal dependencies. ===Relation to BIP 78 (Payjoin version 1)=== From bc3123e1dab1c5b08d6f934b11b4d741107ac386 Mon Sep 17 00:00:00 2001 From: DanGould Date: Fri, 10 May 2024 16:32:27 -0400 Subject: [PATCH 22/50] fix links --- bip-0077.mediawiki | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index 681a66f3fa..f190fc5e04 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -12,7 +12,7 @@ ==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 which 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. +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 which 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== @@ -24,15 +24,15 @@ Payjoin is the simplest case of interactive bitcoin batching, allowing two parti The payjoin protocols automate cooperative transaction construction to break that common-input assumption. The increased the opportunity to batch payments and and execute transaction cut-through increases intent throughput, since multiple intents combined take up fewer bytes than independent transactions. -Version 1's requirements have proven to be an obstacle to adoption. V1 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. +Version 1's requirements have proven to be an obstacle to adoption. V1 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.linuxfuihjknhoundation.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 viable to implement in a majority of bitcoin software environments. This is realized as a simple protocol built on bitcoin URI requests, web standards, common crypto, 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. This protocol also upgrades to PSBT version 2 to simplify transaction construction. +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. This protocol also upgrades to PSBT version 2 to simplify transaction construction. -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 Payjoin 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 while using a directory relay without compromising sender or receiver privacy. +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 Payjoin 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 while using a directory relay 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 stealing funds. @@ -40,7 +40,7 @@ The protocols in this document reuse BIP 78's BIP 21 URI parameters. A Original ===Relation to Stowaway=== -[[https://docs.samourai.io/en/spend-tools#stowaway Stowaway]] was a payjoin coordination mechanism which depends 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. +[[https://docs.samourai.io/en/spend-tools#stowaway| Stowaway]] was a payjoin coordination mechanism which depends 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== @@ -52,7 +52,7 @@ Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP e 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, they start a session to receive messages and allocate a subdirectory from which to relay messages. The first message must include their pubkey to be enrolled as a subdirectory identifier. The response message from the directory to receiver includes the newly enrolled subdirectory payjoin endpoint with the pubkey as identifying subdirectory. After enrollment, they await a payjoin request on a session identified by the subdirectory. 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 ohttp= parameter including the payjoin directory's [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration OHTTP Key Configuration]]. +Rather than hosting a public server, they start a session to receive messages and allocate a subdirectory from which to relay messages. The first message must include their pubkey to be enrolled as a subdirectory identifier. The response message from the directory to receiver includes the newly enrolled subdirectory payjoin endpoint with the pubkey as identifying subdirectory. After enrollment, they await a payjoin request on a session identified by the subdirectory. 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 ohttp= parameter including the payjoin directory's [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| OHTTP Key Configuration]]. The sender constructs an encrypted and authenticated payload containing a PSBT and optional parameters similar to BIP 78. The resulting ciphertext ensures message secrecy and integrity when passed to the recipient by the subdirectory pj= endpoint. @@ -102,16 +102,16 @@ Key: ===Payjoin version 2 messaging=== -Payjoin v2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki BIP 370 PSBT v2]] format to facilitate PSBT mutation. +Payjoin v2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki| BIP 370 PSBT v2]] format to facilitate PSBT mutation. The payjoin version 2 protocol takes the following steps: * The recipient sends their payjoin pubkey and optional authentication credential according to the [[#enroll-messaging|enroll messaging]] protocol to receive a subdirectory allocation. It may go offline and replay enrollment to come back online. * Out of band, the receiver of the payment, shares a bitcoin URI with the sender including a pj= query parameter including the subdirectory as a base64URL encoded pubkey. 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. An ohttp= parameter containing the directory's base64URL Key Config should also be provided. -* The sender creates a valid version 2 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, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#send-messaging|Original PSBT Request send message]] is sent to the directory's OHTTP Gateway. +* The sender creates a valid version 2 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, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#send-messaging|Original PSBT Request send message]] is sent to the directory's OHTTP Gateway. * The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry. * The request is stored in the subdirectory. -* Once the receiver is online, it sends /receive requests to await updates from 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]]. It updates the Original PSBT to include new signed inputs and outputs, invalidating sender signatures, and may adjust the fee. The result is called the Payjoin PSBT. +* Once the receiver is online, it sends /receive requests to await updates from 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]]. It updates the Original PSBT to include new signed inputs and outputs, invalidating sender signatures, and may adjust the fee. The result is called the Payjoin PSBT. * The Payjoin PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and sent to the directory's OHTTP Gateway. * The directory awaits a request from the sender if it goes offline. Upon request, it relays the encrypted Payjoin PSBT. * The sender validates the Payjoin PSBT according to [[#senders-payjoin-psbt-checklist|the sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network. @@ -148,7 +148,7 @@ The Payjoin PSBT MUST NOT: Receivers must enroll with a directory to have a subdirectory allocated to them as follows. -A receiver must first discover the directory's OHTTP gateway key configuration via an authenticated bootstrap mechanism before it can enroll 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. +A receiver must first discover the directory's OHTTP gateway key configuration via an authenticated bootstrap mechanism before it can enroll 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. Payjoin sessions begin by having a receiver send the static pubkey to the directory via OHTTP, receiving their subdirectory in a base64URL encoded directory url as response. Enrollment may be replayed in case the receiver goes offline and should result in the same response. @@ -170,11 +170,11 @@ Once an Original PSBT Payload is decrypted and checked according to the list, th ===Receiver's Payjoin PSBT checklist=== -Other than requiring PSBTv2 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]] +Other than requiring PSBTv2 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]] ===Sender's Payjoin 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 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 headaches since it required the sender to add them back to the Payjoin proposal PSBT. Version 2 has no such requirement. +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 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 headaches since it required the sender to add them back to the Payjoin proposal PSBT. Version 2 has no such requirement. ===Directory interactions=== @@ -188,7 +188,7 @@ Each receiver subdirectory allocated on the directory has a buffer for requests A major benefit of BIP 78 payjoin over other coordination mechanisms is its compatibility with the universal BIP 21 bitcoin URI standard. -This proposal defines the following new [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki BIP 21 URI]] parameters: +This proposal defines the following new [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki| BIP 21 URI]] parameters: * ohttp represents the OHTTP Key Configuration of the directory. This is a base64URL encoded public key of the directory's OHTTP Gateway. This parameter is required for version 2 payjoin URIs. * exp: represents a request expiration 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. @@ -232,15 +232,15 @@ All cyphertexts should be padded to the same length of 7168 bytes to prevent tra Hybrid Public Key Encryption 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 v2 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/NKpsk0/ IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static keys shared in URIs must only for a single 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. +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/NKpsk0/| IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static keys shared in URIs must only for a single 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. +[[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 seems to be making its way into bitcoin by way of [[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. +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 seems to be making its way into bitcoin by way of [[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==== @@ -266,7 +266,7 @@ Unlike BIP 78 implementations, sender and receiver peers will only see the IP ad ==Backwards compatibility== -The receivers advertise payjoin capabilities through [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki BIP21's URI Scheme]]. +The receivers advertise payjoin capabilities through [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki| BIP21's URI Scheme]]. Senders not supporting payjoin will just ignore the pj= parameter and proceed to typical address-based transaction flows. req-pj= may be used to compel payjoin. From 35ebad8ea2bd51fed9a796da5f16a6f62c5e4aa6 Mon Sep 17 00:00:00 2001 From: DanGould Date: Tue, 21 May 2024 11:17:05 -0400 Subject: [PATCH 23/50] Keyconfig s/should/must/ be provided --- bip-0077.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index f190fc5e04..d4b5b991f5 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -107,7 +107,7 @@ Payjoin v2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.m The payjoin version 2 protocol takes the following steps: * The recipient sends their payjoin pubkey and optional authentication credential according to the [[#enroll-messaging|enroll messaging]] protocol to receive a subdirectory allocation. It may go offline and replay enrollment to come back online. -* Out of band, the receiver of the payment, shares a bitcoin URI with the sender including a pj= query parameter including the subdirectory as a base64URL encoded pubkey. 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. An ohttp= parameter containing the directory's base64URL Key Config should also be provided. +* Out of band, the receiver of the payment, shares a bitcoin URI with the sender including a pj= query parameter including the subdirectory as a base64URL encoded pubkey. 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. An ohttp= parameter containing the directory's base64URL Key Config must also be provided. * The sender creates a valid version 2 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, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#send-messaging|Original PSBT Request send message]] is sent to the directory's OHTTP Gateway. * The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry. * The request is stored in the subdirectory. From 224208c270cdb40f945af826253baa9cf4da8614 Mon Sep 17 00:00:00 2001 From: DanGould Date: Tue, 21 May 2024 11:22:11 -0400 Subject: [PATCH 24/50] Fix typos Co-authored-by: thebrandonlucas <38222767+thebrandonlucas@users.noreply.github.com> --- bip-0077.mediawiki | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index d4b5b991f5..c9c41f1f86 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -22,9 +22,9 @@ This BIP is licensed under the 2-clause BSD license. 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 the opportunity to batch payments and and execute transaction cut-through increases intent throughput, since multiple intents combined take up fewer bytes than independent transactions. +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. -Version 1's requirements have proven to be an obstacle to adoption. V1 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.linuxfuihjknhoundation.org/pipermail/bitcoin-dev/2021-January/018358.html| regard]] these as limits to payjoin adoption. +Version 1's requirements have proven to be an obstacle to adoption. V1 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 viable to implement in a majority of bitcoin software environments. This is realized as a simple protocol built on bitcoin URI requests, web standards, common crypto, and minimal dependencies. @@ -107,7 +107,7 @@ Payjoin v2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.m The payjoin version 2 protocol takes the following steps: * The recipient sends their payjoin pubkey and optional authentication credential according to the [[#enroll-messaging|enroll messaging]] protocol to receive a subdirectory allocation. It may go offline and replay enrollment to come back online. -* Out of band, the receiver of the payment, shares a bitcoin URI with the sender including a pj= query parameter including the subdirectory as a base64URL encoded pubkey. 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. An ohttp= parameter containing the directory's base64URL Key Config must also be provided. +* Out of band, the receiver of the payment shares a bitcoin URI with the sender including a pj= query parameter where the subdirectory is a base64URL encoded pubkey. 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. An ohttp= parameter containing the directory's base64URL Key Config must also be provided. * The sender creates a valid version 2 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, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#send-messaging|Original PSBT Request send message]] is sent to the directory's OHTTP Gateway. * The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry. * The request is stored in the subdirectory. From d7ffad81e605e958dcf7c2ae1f4c797a8631f146 Mon Sep 17 00:00:00 2001 From: DanGould Date: Tue, 21 May 2024 11:23:17 -0400 Subject: [PATCH 25/50] s/pubkey/public key --- bip-0077.mediawiki | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index c9c41f1f86..fcaf3c50b7 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -52,7 +52,7 @@ Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP e 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, they start a session to receive messages and allocate a subdirectory from which to relay messages. The first message must include their pubkey to be enrolled as a subdirectory identifier. The response message from the directory to receiver includes the newly enrolled subdirectory payjoin endpoint with the pubkey as identifying subdirectory. After enrollment, they await a payjoin request on a session identified by the subdirectory. 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 ohttp= parameter including the payjoin directory's [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| OHTTP Key Configuration]]. +Rather than hosting a public server, they start a session to receive messages and allocate a subdirectory from which to relay messages. The first message must include their public key to be enrolled as a subdirectory identifier. The response message from the directory to receiver includes the newly enrolled subdirectory payjoin endpoint with the public key as identifying subdirectory. After enrollment, they await a payjoin request on a session identified by the subdirectory. 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 ohttp= parameter including the payjoin directory's [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| OHTTP Key Configuration]]. The sender constructs an encrypted and authenticated payload containing a PSBT and optional parameters similar to BIP 78. The resulting ciphertext ensures message secrecy and integrity when passed to the recipient by the subdirectory pj= endpoint. @@ -106,8 +106,8 @@ Payjoin v2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.m The payjoin version 2 protocol takes the following steps: -* The recipient sends their payjoin pubkey and optional authentication credential according to the [[#enroll-messaging|enroll messaging]] protocol to receive a subdirectory allocation. It may go offline and replay enrollment to come back online. -* Out of band, the receiver of the payment shares a bitcoin URI with the sender including a pj= query parameter where the subdirectory is a base64URL encoded pubkey. 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. An ohttp= parameter containing the directory's base64URL Key Config must also be provided. +* The recipient sends their payjoin public key and optional authentication credential according to the [[#enroll-messaging|enroll messaging]] protocol to receive a subdirectory allocation. It may go offline and replay enrollment to come back online. +* Out of band, the receiver of the payment shares a bitcoin URI with the sender including a pj= query parameter where the subdirectory is a base64URL encoded public key. 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. An ohttp= parameter containing the directory's base64URL Key Config must also be provided. * The sender creates a valid version 2 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, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#send-messaging|Original PSBT Request send message]] is sent to the directory's OHTTP Gateway. * The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry. * The request is stored in the subdirectory. @@ -150,7 +150,7 @@ Receivers must enroll with a directory to have a subdirectory allocated to them A receiver must first discover the directory's OHTTP gateway key configuration via an authenticated bootstrap mechanism before it can enroll 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. -Payjoin sessions begin by having a receiver send the static pubkey to the directory via OHTTP, receiving their subdirectory in a base64URL encoded directory url as response. Enrollment may be replayed in case the receiver goes offline and should result in the same response. +Payjoin sessions begin by having a receiver send the static public key to the directory via OHTTP, receiving their subdirectory in a base64URL encoded directory url as response. Enrollment may be replayed in case the receiver goes offline and should result in the same response. Optionally, before returning the uri the receiver may request an authentication token by presenting a message containing only the word Authenticate: after which the receiver is required to submit an Authenticate: including the token from the directory out of band. If authentication fails an error is returned. @@ -158,7 +158,7 @@ In the case a directory is operated by an exchange, it may give out authenticati ====Send Messaging==== -The version 2 Original PSBT is placed in an HTTP POST request body as binary before being encoded into BHTTP and encrypted according to the HPKE protocol. This Original PSBT BHTTP Request is then encrypted according to the HPKE, generating an ephemeral keypair e from which it derives a shared secret es with the receiver's key s. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Original PSBT BHTTP Request and serialized ephemeral key e's pubkey as associated data using ChaCha20Poly1305. A payload is constructed by concatenating the ephemeral pubkey, the nonce, and the ciphertext. This payload is then sent to the directory in an OHTTP request encapsulating the binary payload. +The version 2 Original PSBT is placed in an HTTP POST request body as binary before being encoded into BHTTP and encrypted according to the HPKE protocol. This Original PSBT BHTTP Request is then encrypted according to the HPKE, generating an ephemeral keypair e from which it derives a shared secret es with the receiver's key s. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Original PSBT BHTTP Request and serialized 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 payload is then sent to the directory in an OHTTP request encapsulating the binary payload. The directory's OHTTP Gateway decapsulates the OHTTP request, decrypts the payload, and forwards the BHTTP POST request to the receiver's internal subdirectory endpoint which stores the HPKE encrypted payload to be forwarded to the receiver. The directory's OHTTP Gateway then awaits a response from the receiver's subdirectory endpoint, encapsulates it, and responds according to OHTTP. @@ -166,7 +166,7 @@ The directory's OHTTP Gateway decapsulates the OHTTP request, decrypts the paylo The receiver sends a GET request to the path of the subdirectory followed by /receive. This request is encapsulated in OHTTP. It awaits an OHTTP response from the directory containing the BHTTP request from the sender with status code 200 OK, or sends a new OHTTP request after receiving 202 ACCEPTED notifying the receiver that the directory has not yet received an request from the sender. -Once an Original PSBT Payload is decrypted and checked according to the list, the receiver may respond with a Payjoin PSBT. The receiver encrypts the PSBT according to the HPKE protocol, generating an ephemeral keypair e from which it derives a shared secret ee with the sender's key e from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Payjoin PSBT and serialized receiver ephemeral key e's pubkey as associated data using ChaCha20Poly1305. A payload is constructed by concatenating the ephemeral pubkey, the nonce, and the ciphertext. This payload is then sent to the directory in an OHTTP request encapsulating the binary payload as a POST message to the subdirectory followed by /receive. +Once an Original PSBT Payload is decrypted and checked according to the list, the receiver may respond with a Payjoin PSBT. The receiver encrypts the PSBT according to the HPKE protocol, generating an ephemeral keypair e from which it derives a shared secret ee with the sender's key e from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Payjoin 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 payload is then sent to the directory in an OHTTP request encapsulating the binary payload as a POST message to the subdirectory followed by /receive. ===Receiver's Payjoin PSBT checklist=== From 3b863a402e0250658985f08a455a6cd103e269e5 Mon Sep 17 00:00:00 2001 From: DanGould Date: Sun, 2 Jun 2024 14:27:37 -0400 Subject: [PATCH 26/50] Incorporate jonatack's suggestions --- bip-0077.mediawiki | 69 +++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index fcaf3c50b7..1d97766c92 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -12,7 +12,7 @@ ==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 which 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. +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== @@ -24,23 +24,23 @@ Payjoin is the simplest case of interactive bitcoin batching, allowing two parti 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. -Version 1's requirements have proven to be an obstacle to adoption. V1 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. +Payjoin V1's requirements have proven to be an obstacle to adoption. V1 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 viable to implement in a majority of bitcoin software environments. This is realized as a simple protocol built on bitcoin URI requests, web standards, common crypto, and minimal dependencies. +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. This protocol also upgrades to PSBT version 2 to simplify transaction construction. +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. This protocol also upgrades to [[https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki| PSBT Version 2]] to simplify transaction construction. 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 Payjoin 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 while using a directory relay 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 stealing funds. -The protocols in this document reuse BIP 78's BIP 21 URI parameters. A Original PSBT timeout parameter is introduced which may also help coordinate the synchronous version 1 protocol. +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 which depends 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. +[[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== @@ -52,9 +52,9 @@ Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP e 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, they start a session to receive messages and allocate a subdirectory from which to relay messages. The first message must include their public key to be enrolled as a subdirectory identifier. The response message from the directory to receiver includes the newly enrolled subdirectory payjoin endpoint with the public key as identifying subdirectory. After enrollment, they await a payjoin request on a session identified by the subdirectory. 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 ohttp= parameter including the payjoin directory's [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| OHTTP Key Configuration]]. +Rather than hosting a public server, the receiver starts a session to receive messages and allocates a subdirectory from which to relay messages. The first message must include the receiver's public key to be enrolled as a subdirectory identifier. The response message from the directory to the receiver includes the newly enrolled subdirectory payjoin endpoint with the public key as identifying subdirectory. After enrollment, the receiver awaits a payjoin request on a session identified by the subdirectory. 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= parameter including the payjoin directory's [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| OHTTP Key Configuration]]. -The sender constructs an encrypted and authenticated payload containing a PSBT and optional parameters similar to BIP 78. The resulting ciphertext ensures message secrecy and integrity when passed to the recipient by the subdirectory pj= endpoint. +The sender constructs an encrypted and authenticated 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. @@ -102,18 +102,18 @@ Key: ===Payjoin version 2 messaging=== -Payjoin v2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki| BIP 370 PSBT v2]] format to facilitate PSBT mutation. +Payjoin V2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki| BIP 370 PSBT V2]] format to facilitate [[#psbt-version-2|PSBT mutation]]. The payjoin version 2 protocol takes the following steps: -* The recipient sends their payjoin public key and optional authentication credential according to the [[#enroll-messaging|enroll messaging]] protocol to receive a subdirectory allocation. It may go offline and replay enrollment to come back online. -* Out of band, the receiver of the payment shares a bitcoin URI with the sender including a pj= query parameter where the subdirectory is a base64URL encoded public key. 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. An ohttp= parameter containing the directory's base64URL Key Config must also be provided. +* The receiver sends their payjoin public key and optional authentication credential according to the [[#enroll-messaging|enroll messaging]] protocol to receive a subdirectory allocation. The receiver may go offline and replay enrollment to come back online. +* Out of band, the receiver shares a bitcoin URI with the sender, including a pj= query parameter where the subdirectory is the session public key. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5| base64url]] encoding. 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. An ohttp= parameter containing the directory's base64url encoded [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| Oblivious HTTP Key Configuration]] must also be provided. * The sender creates a valid version 2 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, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#send-messaging|Original PSBT Request send message]] is sent to the directory's OHTTP Gateway. * The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry. * The request is stored in the subdirectory. -* Once the receiver is online, it sends /receive requests to await updates from 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]]. It updates the Original PSBT to include new signed inputs and outputs, invalidating sender signatures, and may adjust the fee. The result is called the Payjoin PSBT. +* Once the receiver is online, it sends [[#receive-messaging|/receive]] requests to await updates from 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 Payjoin PSBT. * The Payjoin PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and sent to the directory's OHTTP Gateway. -* The directory awaits a request from the sender if it goes offline. Upon request, it relays the encrypted Payjoin PSBT. +* The directory awaits a request from the sender if it goes offline. Upon request, the directory relays the encrypted Payjoin PSBT. * The sender validates the Payjoin PSBT according to [[#senders-payjoin-psbt-checklist|the sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network. The Original PSBT MUST: @@ -121,13 +121,13 @@ The Original PSBT MUST: * Include complete UTXO data. * Be signed. * Exclude unnecessary fields such as global xpubs or keypath information. -* Set input and output Transaction Modifiable Flags to 1 +* Set input and output Transaction Modifiable Flags to 1. * Be broadcastable. The Original PSBT MAY: * Include outputs unrelated to the sender-receiver transfer for batching purposes. -* Set SIGHASH_SINGLE Transaction Modifiable Flags flags to 1 +* Set SIGHASH_SINGLE Transaction Modifiable Flags flags to 1. The Payjoin PSBT MUST: @@ -146,43 +146,44 @@ The Payjoin PSBT MUST NOT: ====Enroll Messaging==== -Receivers must enroll with a directory to have a subdirectory allocated to them as follows. +Receivers must enroll with a directory to have a subdirectory allocated to them, as follows: A receiver must first discover the directory's OHTTP gateway key configuration via an authenticated bootstrap mechanism before it can enroll 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. -Payjoin sessions begin by having a receiver send the static public key to the directory via OHTTP, receiving their subdirectory in a base64URL encoded directory url as response. Enrollment may be replayed in case the receiver goes offline and should result in the same response. +Payjoin sessions begin by having a receiver send the static public key to the directory via OHTTP, receiving their subdirectory in a base64url encoded directory url as response. Enrollment may be replayed in case the receiver goes offline and should result in the same response. -Optionally, before returning the uri the receiver may request an authentication token by presenting a message containing only the word Authenticate: after which the receiver is required to submit an Authenticate: including the token from the directory out of band. If authentication fails an error is returned. +Optionally, before returning the URI, the receiver may request an authentication token by presenting a message containing only the word Authenticate: , after which the receiver is required to submit an Authenticate: including the token from the directory out of band. If authentication fails, an error is returned. -In the case a directory is operated by an exchange, it may give out authentication tokens for users of its app, or may require some proof of work out of band. Tokens should be anonymous credentials from the directory describing the parameters of their authorization. Specific credentialing is out of the scope of this proposal. +If a directory is operated by an exchange, it may give out authentication tokens for users of its app, or may require some proof of work out of band. Tokens should be anonymous credentials from the directory describing the parameters of their authorization. Specific credentialing is out of the scope of this proposal. ====Send Messaging==== -The version 2 Original PSBT is placed in an HTTP POST request body as binary before being encoded into BHTTP and encrypted according to the HPKE protocol. This Original PSBT BHTTP Request is then encrypted according to the HPKE, generating an ephemeral keypair e from which it derives a shared secret es with the receiver's key s. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Original PSBT BHTTP Request and serialized 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 payload is then sent to the directory in an OHTTP request encapsulating the binary payload. +The version 2 Original PSBT is serialized in base64 followed by the query parameter string on a new line. This plaintext string encrypted according to the HPKE using a shared secret derived from a newly generated session keypair public key combined with the receiver's subdirectory 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. -The directory's OHTTP Gateway decapsulates the OHTTP request, decrypts the payload, and forwards the BHTTP POST request to the receiver's internal subdirectory endpoint which stores the HPKE encrypted payload to be forwarded to the receiver. The directory's OHTTP Gateway then awaits a response from the receiver's subdirectory endpoint, encapsulates it, and responds according to OHTTP. +The directory's OHTTP Gateway decapsulates the OHTTP request, handles the POST request at the receiver's internal subdirectory endpoint, which stores the HPKE encrypted payload to be forwarded to the receiver. The directory's awaits a request from the receiver's to the subdirectory endpoint, encapsulates to responds with the HPKE encrypted Original PSBT payload acording to OHTTP. ====Receive Messaging==== -The receiver sends a GET request to the path of the subdirectory followed by /receive. This request is encapsulated in OHTTP. It awaits an OHTTP response from the directory containing the BHTTP request from the sender with status code 200 OK, or sends a new OHTTP request after receiving 202 ACCEPTED notifying the receiver that the directory has not yet received an request from the sender. +The receiver sends a GET request to the path of the subdirectory followed by /receive. This request is encapsulated in OHTTP. +The recver then awaits an OHTTP response from the directory encapsulating a request from the sender with status code 200 OK, or sends 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. -Once an Original PSBT Payload is decrypted and checked according to the list, the receiver may respond with a Payjoin PSBT. The receiver encrypts the PSBT according to the HPKE protocol, generating an ephemeral keypair e from which it derives a shared secret ee with the sender's key e from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Payjoin 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 payload is then sent to the directory in an OHTTP request encapsulating the binary payload as a POST message to the subdirectory followed by /receive. +Once an Original PSBT Payload is decrypted and checked according to the [[#receivers-payjoin-psbt-checklist|checklist]], the receiver should respond with a Payjoin PSBT or an error. The receiver encrypts the PSBT according to the HPKE protocol, generating an ephemeral keypair e from which it derives a shared secret ee with the sender's key e from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Payjoin 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 payload is then sent to the directory in an OHTTP request encapsulating the binary payload as a POST message to the subdirectory followed by /receive. ===Receiver's Payjoin PSBT checklist=== -Other than requiring PSBTv2 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]] +Other than requiring PSBTv2, 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]] ===Sender's Payjoin 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 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 headaches since it required the sender to add them back to the Payjoin proposal PSBT. Version 2 has no such requirement. +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 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. It stores Payjoin payloads to support asynchronous communication. It must only accept OHTTP requests with an OHTTP Gateway for Payjoin version 2, accepting encrypted payloads. It may optionally accept HTTP/1.1 POST requests without HTTP to enrolled subdirectories to support backwards compatible Payjoin version 1 requests. +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 HTTP to enrolled subdirectories to support backwards compatible Payjoin version 1 requests. ===Subdirectories=== -Each receiver subdirectory allocated on the directory has a buffer for requests and one for responses. Each buffer updates listeners through awaitable events so that updates are immediately apparent upon client request. +Each receiver subdirectory allocated on the directory has one buffer for requests and one for responses. Each buffer updates listeners through awaitable events so that updates are immediately apparent upon client request. ===BIP 21 receiver parameters=== @@ -190,12 +191,12 @@ A major benefit of BIP 78 payjoin over other coordination mechanisms is its comp This proposal defines the following new [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki| BIP 21 URI]] parameters: -* ohttp represents the OHTTP Key Configuration of the directory. This is a base64URL encoded public key of the directory's OHTTP Gateway. This parameter is required for version 2 payjoin URIs. +* ohttp represents the OHTTP Key Configuration of the directory. This is a base64url encoded public key of the directory's OHTTP Gateway. This parameter is required for version 2 payjoin URIs. * exp: represents a request expiration 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. ===Optional sender parameters=== -When the payjoin sender posts the original PSBT to the receiver, it can optionally specify the following HTTP query string parameters: +When the payjoin sender posts the 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. @@ -207,15 +208,15 @@ BIP 78's optional query parameters are also valid as version 2 parameters. The directory may hold a request for an offline payjoin peer until that peer comes online. However, the BIP 78 spec recommends broadcasting request 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 Original PSBT from which a valid payment transaction may be extracted that would not preserve privacy the same way as a payjoin. BIP 21 URI 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=. +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 is eligible to enjoy metadata protection from Oblivious 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 from both one another and from the directory. This makes it more difficult for a directory to correlate many payjoin transactions with a specific IP addresses by intersection. +OHTTP protects sender and receiver IP addresses from both 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. @@ -232,7 +233,7 @@ All cyphertexts should be padded to the same length of 7168 bytes to prevent tra Hybrid Public Key Encryption 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 v2 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/NKpsk0/| IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static keys shared in URIs must only for a single 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. +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/NKpsk0/| IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static keys shared in URIs must only for a single 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==== @@ -282,4 +283,4 @@ Independent Oblivious HTTP relays are run by Obscura VPN at https://ohttp-relay. ==Acknowledgements== -Thank you to OpenSats for funding this pursuit, to Human Rights Foundation for putting a bounty on it and funding invaluable BOB Space space support, who I owe a thank you to as well. Thank you to Ethan Heilman, Nicolas Dorier, Kukks, nopara73, Kristaps Kaupe, Kixunil, /dev/fd0/, Craig Raw, Mike Schmidt, Murch, Dávid Molnár, Lucas Ontiviero, Waxwing, Christopher Allen, Symphonic, Steve Meyers, Sjors Provost, Ava Chow, jbesraa, and countless plebs for feedback that has turned this idea from concept into draft, to Mike Jarmuz for suggesting that I write a BIP, and to Satsie for writing the "All About BIPS" zine which I've referenced a number of times in the drafting process. Thanks to Armin Sabouri, Ron Stoner, and Johns Beharry for hacking on the first iOS Payjoin receiver and uncovering the problem that this solves in the first place. +Thank you to OpenSats for funding this pursuit, to Human Rights Foundation for putting a bounty on it and funding invaluable BOB Space support, who I owe a thank you to as well. Thank you to Ethan Heilman, Nicolas Dorier, Kukks, nopara73, Kristaps Kaupe, Kixunil, /dev/fd0/, Craig Raw, Mike Schmidt, Murch, Dávid Molnár, Lucas Ontiviero, Waxwing, Christopher Allen, Symphonic, Steve Meyers, Sjors Provost, Ava Chow, jbesraa, and countless plebs for feedback that has turned this idea from concept into draft, to Mike Jarmuz for suggesting that I write a BIP, and to Satsie for writing the "All About BIPS" zine which I've referenced a number of times in the drafting process. Thanks to Armin Sabouri, Ron Stoner, and Johns Beharry for hacking on the first iOS Payjoin receiver and uncovering the problem that this solves in the first place. From f86fe4150ba6bfe9622ff36f989de1c15e52fcc4 Mon Sep 17 00:00:00 2001 From: DanGould Date: Sat, 6 Jul 2024 12:39:39 -0400 Subject: [PATCH 27/50] Incorporate more jonatack suggestions --- bip-0077.mediawiki | 48 +++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index 1d97766c92..223b2ddff3 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -158,14 +158,14 @@ If a directory is operated by an exchange, it may give out authentication tokens ====Send Messaging==== -The version 2 Original PSBT is serialized in base64 followed by the query parameter string on a new line. This plaintext string encrypted according to the HPKE using a shared secret derived from a newly generated session keypair public key combined with the receiver's subdirectory 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. +The version 2 Original PSBT is serialized in base64, followed by the query parameter string on a new line. This plaintext string is encrypted according to the HPKE using a shared secret derived from a newly generated session keypair public key combined with the receiver's subdirectory 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. -The directory's OHTTP Gateway decapsulates the OHTTP request, handles the POST request at the receiver's internal subdirectory endpoint, which stores the HPKE encrypted payload to be forwarded to the receiver. The directory's awaits a request from the receiver's to the subdirectory endpoint, encapsulates to responds with the HPKE encrypted Original PSBT payload acording to OHTTP. +Upon receipt, the directory's OHTTP Gateway decapsulates the OHTTP request and handles the inner POST request at the session subdirectory endpoint, which stores the HPKE encrypted payload to be forwarded to the receiver. The directory's OHTTP Gateway awaits a request from the receiver to the session subdirectory endpoint and responds with the HPKE encrypted Original PSBT payload acording to OHTTP. ====Receive Messaging==== The receiver sends a GET request to the path of the subdirectory followed by /receive. This request is encapsulated in OHTTP. -The recver then awaits an OHTTP response from the directory encapsulating a request from the sender with status code 200 OK, or sends 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. +The receiver then awaits an OHTTP response from the directory encapsulating a request from the sender with status code 200 OK, or sends 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. Once an Original PSBT Payload is decrypted and checked according to the [[#receivers-payjoin-psbt-checklist|checklist]], the receiver should respond with a Payjoin PSBT or an error. The receiver encrypts the PSBT according to the HPKE protocol, generating an ephemeral keypair e from which it derives a shared secret ee with the sender's key e from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Payjoin 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 payload is then sent to the directory in an OHTTP request encapsulating the binary payload as a POST message to the subdirectory followed by /receive. @@ -175,7 +175,7 @@ Other than requiring PSBTv2, the receiver checklist is the same as the [[https:/ ===Sender's Payjoin 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 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. +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 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=== @@ -191,8 +191,8 @@ A major benefit of BIP 78 payjoin over other coordination mechanisms is its comp This proposal defines the following new [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki| BIP 21 URI]] parameters: -* ohttp represents the OHTTP Key Configuration of the directory. This is a base64url encoded public key of the directory's OHTTP Gateway. This parameter is required for version 2 payjoin URIs. -* exp: represents a request expiration 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. +* ohttp: represents the OHTTP Key Configuration of the directory. This is a base64url encoded public key of the directory's OHTTP Gateway. 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. ===Optional sender parameters=== @@ -206,9 +206,9 @@ BIP 78's optional query parameters are also valid as version 2 parameters. ===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 recommends broadcasting request PSBTs in the case of an offline counterparty. Doing so exposes a naïve, surveillance-vulnerable transaction which payjoin intends to avoid. +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 request 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=. +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=== @@ -231,9 +231,9 @@ All cyphertexts should be padded to the same length of 7168 bytes to prevent tra ===Secp256k1 Hybrid Public Key Encryption=== -Hybrid Public Key Encryption 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 v2 application specific configuration to use DHKEM(Secp256k1, HKDF-SHA256) and ChaCha20Poly1305 AEAD. +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 v2 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/NKpsk0/| IK]] pattern. A receiver shares its public key out of band in the BIP21 URI. Static keys shared in URIs must only for a single 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. +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/NKpsk0/| 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 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==== @@ -241,7 +241,7 @@ The cryptographic handshake is conducted in parallel to the payjoin messaging in ====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 seems to be making its way into bitcoin by way of [[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. +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==== @@ -249,38 +249,34 @@ SHA-256 is considered secure and is necessarily available in bitcoin contexts. ===PSBT Version 2=== -The PSBT version 1 protocol was replaced because it was not designed to have inputs and outputs be mutated. Payjoin mutates the PSBT, so BIP 78 uses a hack where a new PSBT is created by the receiver instead of mutating it. This can cause some strange behaviors from signers who don't know where to look to find the scripts that they are accountable for. PSBT version 2 makes mutating a PSBT's inputs and outputs trivial. It also eliminates the transaction finalization step. Receivers who do not understand PSBT version 1 may choose to reject Payjoin version 1 requests and only support PSBT version 2. +The PSBT version 1 protocol was replaced because it was not designed to have inputs and outputs be mutated. Payjoin mutates the PSBT, so BIP 78 uses a workaround where a new PSBT is created by the receiver instead of mutating it. This can cause strange behaviors from signers who don't know where to look to find the scripts that they are accountable for. PSBT version 2 makes mutating a PSBT's inputs and outputs trivial. It also eliminates the transaction finalization step. Receivers who do not understand PSBT version 1 may choose to reject Payjoin version 1 requests and only support PSBT version 2. ===Attack vectors=== -Since directories store arbitrary encrypted payloads they are vulnerable to the tragedy of the commons and denial of service attacks. Directory operators may impose an authentication requirement before they allocate a subdirectory to receivers to mitigate such attacks. +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 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. -Since the Original PSBT is valid, even where exp= is specified, the receiver may broadcast it and lose out on savings from payment batching and privacy protection from payjoin structure at any time. Though unfortunate, this failure mode is the typical bitcoin transaction flow today anyhow. +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 Payjoin PSBT and wait for a signature once a Payjoin 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 address of both sender and receiver from the directory. This requires an additional key configuration to be shared in the bip21 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. +Oblivious HTTP must be used to protect the IP address of both sender and receiver from the directory. This requires an additional 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, not their peers. Directories may additionally be made available via Tor hidden service to allow either of the peers to protect their IP from the directory without OHTTP. +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| BIP21's URI Scheme]]. +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. req-pj= may be used to compel payjoin. +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 should enable pjos=0 so that these v1 senders disable output substitution since the v1 messages are neither encrypted nor authenticated, putting them at risk for man-in-the-middle attacks otherwise. 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 Payjoin PSBTs to the same subdirectory as in version 2 to respond to these version 1 senders within 30 seconds to respond to the sender's request. +Receivers may choose to support version 1 payloads. Version 2 payjoin URIs for backwards compatible receivers MUST enable pjos=0 so that these v1 senders disable output substitution. Since the v1 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 Payjoin 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 implements an asynchronous payment flow using HTTP using PSBTv1 with encryption and Oblivious HTTP and may be configured to the following independent production relays: +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 implements an asynchronous payment flow using HTTP using PSBTv1 with encryption and Oblivious HTTP and may be configured to the following independent production relays: -A payjoin directory is run by the Payjoin Dev Kit team on https://payjo.in. +A payjoin directory is run by the Payjoin Dev Kit team on [[https://payjo.in]]. -Independent Oblivious HTTP relays are run by Obscura VPN at https://ohttp-relay.obscuravpn.io/payjoin and by BOB Spaces at https://pj.bobspacebkk.com. - -==Acknowledgements== - -Thank you to OpenSats for funding this pursuit, to Human Rights Foundation for putting a bounty on it and funding invaluable BOB Space support, who I owe a thank you to as well. Thank you to Ethan Heilman, Nicolas Dorier, Kukks, nopara73, Kristaps Kaupe, Kixunil, /dev/fd0/, Craig Raw, Mike Schmidt, Murch, Dávid Molnár, Lucas Ontiviero, Waxwing, Christopher Allen, Symphonic, Steve Meyers, Sjors Provost, Ava Chow, jbesraa, and countless plebs for feedback that has turned this idea from concept into draft, to Mike Jarmuz for suggesting that I write a BIP, and to Satsie for writing the "All About BIPS" zine which I've referenced a number of times in the drafting process. Thanks to Armin Sabouri, Ron Stoner, and Johns Beharry for hacking on the first iOS Payjoin receiver and uncovering the problem that this solves in the first place. +An independent Oblivious HTTP relay is run by [[https://www.bobspaces.net| BOB Spaces]] at [[https://pj.bobspacebkk.com]]. From 5c65c2120e0ddc1145ae065b78ad4573a3a3b52e Mon Sep 17 00:00:00 2001 From: DanGould Date: Sat, 6 Jul 2024 19:55:01 -0400 Subject: [PATCH 28/50] Incorporate satsie's suggesetions --- bip-0077.mediawiki | 78 +++++++++++++-------------- bip-0077/oblivious-http-sequence.png | Bin 57987 -> 63078 bytes 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index 223b2ddff3..2b347c588f 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -12,7 +12,7 @@ ==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. +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== @@ -22,9 +22,9 @@ This BIP is licensed under the 2-clause BSD license. 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. +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 V1's requirements have proven to be an obstacle to adoption. V1 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. +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. @@ -32,35 +32,39 @@ The primary goal of this proposal is to provide a practical coordination mechani 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. This protocol also upgrades to [[https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki| PSBT Version 2]] to simplify transaction construction. -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 Payjoin 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 while using a directory relay without compromising sender or receiver privacy. +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 Payjoin 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 while using a directory relay 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 stealing funds. +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 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. +[[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 enroll with a store-and-forward directory server to receive payjoin. 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. +Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP endpoint, this scheme allows an HTTP client to enroll with 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, the receiver starts a session to receive messages and allocates a subdirectory from which to relay messages. The first message must include the receiver's public key to be enrolled as a subdirectory identifier. The response message from the directory to the receiver includes the newly enrolled subdirectory payjoin endpoint with the public key as identifying subdirectory. After enrollment, the receiver awaits a payjoin request on a session identified by the subdirectory. 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= parameter including the payjoin directory's [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| OHTTP Key Configuration]]. +Rather than hosting a public server itself, the receiver initializes a Payjoin Session by requesting a subdirectory allocation at a related to a public key. This key is used to identify a store-and-forward subdirectory on the Payjoin Directory server and establish end-to-end encryption. A POST request to the Payjoin Directory including the receiver's public key enrolls it as a subdirectory identifier. The response message from the directory to the receiver includes the new session subdirectory payjoin endpoint using the public key as a subdirectory identifier. Once 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= parameter including the Payjoin Directory's [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| OHTTP Key Configuration]]. The sender constructs an encrypted and authenticated 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. +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 |
 +----------+                 +-----------+       +--------+  +---------+
@@ -94,20 +98,16 @@ Messages are secured by symmetric cipher rather than TLS or Onion routing sessio
 |                                  |                  +--------------->|
 |                                  |                  |                |
 +                                  +                  +                +
-
-Key: 
-|-----> Single transmission
-|- - -> Polled transmission
 
===Payjoin version 2 messaging=== -Payjoin V2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki| BIP 370 PSBT V2]] format to facilitate [[#psbt-version-2|PSBT mutation]]. +Payjoin version 2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki| BIP 370: PSBT Version 2]] (PSBTv2) format to facilitate [[#psbt-version-2|PSBT mutation]]. -The payjoin version 2 protocol takes the following steps: +The Payjoin version 2 protocol takes the following steps: -* The receiver sends their payjoin public key and optional authentication credential according to the [[#enroll-messaging|enroll messaging]] protocol to receive a subdirectory allocation. The receiver may go offline and replay enrollment to come back online. -* Out of band, the receiver shares a bitcoin URI with the sender, including a pj= query parameter where the subdirectory is the session public key. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5| base64url]] encoding. 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. An ohttp= parameter containing the directory's base64url encoded [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| Oblivious HTTP Key Configuration]] must also be provided. +* The receiver sends their Payjoin Session public key and optional authentication credential according to the [[#enroll-messaging|enroll messaging]] protocol to receive a subdirectory allocation. The receiver may go offline and replay enrollment to come back online. +* Out of band, the receiver shares a bitcoin URI with the sender, including a pj= query parameter where the subdirectory is the Payjoin Session public key. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5| base64url]] encoding. 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. An ohttp= parameter containing the directory's base64url encoded [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| Oblivious HTTP Key Configuration]] must also be provided. * The sender creates a valid version 2 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, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#send-messaging|Original PSBT Request send message]] is sent to the directory's OHTTP Gateway. * The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry. * The request is stored in the subdirectory. @@ -142,15 +142,15 @@ The Payjoin PSBT sender MAY: The Payjoin 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. +* Decrease the absolute fee of the Original PSBT. ====Enroll Messaging==== Receivers must enroll with a directory to have a subdirectory allocated to them, as follows: -A receiver must first discover the directory's OHTTP gateway key configuration via an authenticated bootstrap mechanism before it can enroll 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. +A receiver must first discover the directory's OHTTP gateway Key Configuration via an authenticated bootstrap mechanism before it can enroll 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. -Payjoin sessions begin by having a receiver send the static public key to the directory via OHTTP, receiving their subdirectory in a base64url encoded directory url as response. Enrollment may be replayed in case the receiver goes offline and should result in the same response. +Payjoin Sessions begin by having a receiver send the static public key to the directory via OHTTP, receiving their subdirectory in a base64url encoded directory URL as response. Enrollment may be replayed in case the receiver goes offline and should result in the same response, i.e. it Is idempotent. Optionally, before returning the URI, the receiver may request an authentication token by presenting a message containing only the word Authenticate: , after which the receiver is required to submit an Authenticate: including the token from the directory out of band. If authentication fails, an error is returned. @@ -158,9 +158,9 @@ If a directory is operated by an exchange, it may give out authentication tokens ====Send Messaging==== -The version 2 Original PSBT is serialized in base64, followed by the query parameter string on a new line. This plaintext string is encrypted according to the HPKE using a shared secret derived from a newly generated session keypair public key combined with the receiver's subdirectory 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. +The version 2 Original PSBT is serialized in base64, followed by the query parameter string on a new line. This plaintext string is encrypted according to the HPKE using a shared secret derived from a newly generated Payjoin Session keypair 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. -Upon receipt, the directory's OHTTP Gateway decapsulates the OHTTP request and handles the inner POST request at the session subdirectory endpoint, which stores the HPKE encrypted payload to be forwarded to the receiver. The directory's OHTTP Gateway awaits a request from the receiver to the session subdirectory endpoint and responds with the HPKE encrypted Original PSBT payload acording to OHTTP. +Upon receipt, the directory's OHTTP Gateway decapsulates the OHTTP request and handles the inner POST request at the Payjoin Session subdirectory endpoint, which stores the HPKE encrypted payload to be forwarded to the receiver. The directory's OHTTP Gateway awaits a request from the receiver to the Payjoin Session subdirectory endpoint and responds with the HPKE encrypted Original PSBT payload acording to OHTTP. ====Receive Messaging==== @@ -179,7 +179,7 @@ The version 2 sender's checklist is largely the same as the [[https://github.com ===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 HTTP to enrolled subdirectories to support backwards compatible Payjoin version 1 requests. +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 HTTP to enrolled subdirectories to support backwards compatible Payjoin version 1 requests. ===Subdirectories=== @@ -187,18 +187,18 @@ Each receiver subdirectory allocated on the directory has one buffer for request ===BIP 21 receiver parameters=== -A major benefit of BIP 78 payjoin over other coordination mechanisms is its compatibility with the universal BIP 21 bitcoin URI standard. +A major benefit of BIP 78 Payjoin over other coordination mechanisms is its compatibility with the universal BIP 21 bitcoin URI standard. This proposal defines the following new [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki| BIP 21 URI]] parameters: -* ohttp: represents the OHTTP Key Configuration of the directory. This is a base64url encoded public key of the directory's OHTTP Gateway. This parameter is required for version 2 payjoin URIs. +* ohttp: represents the OHTTP Key Configuration of the directory. This is a base64url encoded public key of the directory's OHTTP Gateway. 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. ===Optional sender parameters=== -When the payjoin sender posts the original PSBT to the receiver, the sender should specify the following HTTP query string 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. +* 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. @@ -206,7 +206,7 @@ BIP 78's optional query parameters are also valid as version 2 parameters. ===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 request PSBTs in the case of an offline counterparty. Doing so exposes a naïve, surveillance-vulnerable transaction which payjoin intends to avoid. +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=. @@ -216,7 +216,7 @@ HTTP is ubiquitous. Using simple HTTP polling allows even Bitcoin Core to consid ===Oblivious HTTP=== -OHTTP protects sender and receiver IP addresses from both 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 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. @@ -227,13 +227,13 @@ OHTTP relays can be run as basic HTTP proxies from wallet providers or third par ===Message Padding=== -All cyphertexts should be padded to the same length of 7168 bytes to prevent traffic analysis. This is sufficient size for most transaction PSBTs without exceeding the 8KB limit of many HTTP/1.1 web servers. +All cyphertexts 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 v2 application specific configuration to use DHKEM(Secp256k1, HKDF-SHA256) and ChaCha20Poly1305 AEAD. +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/NKpsk0/| 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 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. +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/NKpsk0/| 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==== @@ -255,28 +255,28 @@ The PSBT version 1 protocol was replaced because it was not designed to have inp 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 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. +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 Payjoin PSBT and wait for a signature once a Payjoin 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 address of both sender and receiver from the directory. This requires an additional 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. +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]]. +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. +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 v1 senders disable output substitution. Since the v1 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 Payjoin 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]]. +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 Payjoin 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 implements an asynchronous payment flow using HTTP using PSBTv1 with encryption and Oblivious HTTP and may be configured to the following independent production relays: +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 implements an asynchronous payment flow using HTTP using PSBTv1 with encryption and Oblivious HTTP and may be configured to the following independent production relays: -A payjoin directory is run by the Payjoin Dev Kit team on [[https://payjo.in]]. +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 index 53809d7f17470e827ff4fcb1e5ca160d08a0fa47..62e293431dcd4275834b7a436791257cbb6e4787 100644 GIT binary patch literal 63078 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 literal 57987 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 From b701adea506d65cdc9f622bc17337cbddfb6c05d Mon Sep 17 00:00:00 2001 From: DanGould Date: Sun, 14 Jul 2024 22:49:53 -0400 Subject: [PATCH 29/50] Rename "Async Payjoin" --- README.mediawiki | 2 +- bip-0077.mediawiki | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.mediawiki b/README.mediawiki index 1801ebcdb1..34a83ac8c9 100644 --- a/README.mediawiki +++ b/README.mediawiki @@ -402,7 +402,7 @@ Those proposing changes should consider that ultimately consent may rest with th |- | [[bip-0077.mediawiki|77]] | Applications -| Payjoin Version 2: Serverless Payjoin +| Payjoin Version 2 — Async Payjoin | Dan Gould | Standard | Draft diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index 2b347c588f..88ceebb677 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -1,7 +1,7 @@
   BIP: 77
   Layer: Applications
-  Title: Payjoin Version 2: Serverless Payjoin
+  Title: Payjoin Version 2 — Async Payjoin
   Author: Dan Gould 
   Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0077
   Status: Draft

From 93b1e60d8a2b6c879a37d611a591d599612b1fde Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Mon, 15 Jul 2024 11:38:11 -0400
Subject: [PATCH 30/50] Replace BIP21 params with fragment params

---
 bip-0077.mediawiki | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 88ceebb677..50a0b3e7d4 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -185,15 +185,21 @@ The Payjoin Directory provides a rendezvous point for sender and receiver to mee
 
 Each receiver subdirectory allocated on the directory has one buffer for requests and one for responses. Each buffer updates listeners through awaitable events so that updates are immediately apparent upon client request.
 
-===BIP 21 receiver parameters===
+===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.
 
-This proposal defines the following new [[https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki| BIP 21 URI]] parameters:
+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 public key of the directory's OHTTP Gateway. 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 https://payjo.in/A_AIjiMHeXGyelsouuwGLELpdzisOfj8eWzjh2OJ3cim#ohttp%3DAQAgF9BeZJPsVQ4dQ-yFmNE_vAzHHD-CGfcRTOGxCngofR8ABAABAAM%26exp%3D1721098849
+
+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:

From 7e7b3b4bac93a3000cfbf55156122482283cc872 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Mon, 15 Jul 2024 12:58:39 -0400
Subject: [PATCH 31/50] Revise document to describe Payjoin Sessions

Enrollment was a less clear than sessions
---
 bip-0077.mediawiki | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 50a0b3e7d4..a84d4aabd4 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -46,13 +46,13 @@ The protocols in this document reuse BIP 78's BIP 21 URI parameters. An "Origina
 
 ===Overview===
 
-Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP endpoint, this scheme allows an HTTP client to enroll with 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.
+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 at a related to a public key. This key is used to identify a store-and-forward subdirectory on the Payjoin Directory server and establish end-to-end encryption. A POST request  to the Payjoin Directory including the receiver's public key enrolls it as a subdirectory identifier. The response message from the directory to the receiver includes the new session subdirectory payjoin endpoint using the public key as a subdirectory identifier. Once 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= parameter including the Payjoin Directory's [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| OHTTP Key Configuration]].
+Rather than hosting a public server itself, the receiver initializes a Payjoin Session by requesting a subdirectory allocation related to a public key. This 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. The response message from the directory to the receiver includes the new Session subdirectory payjoin endpoint using the public key as a subdirectory identifier. Once 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 encrypted and authenticated 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.
 
@@ -106,7 +106,7 @@ Payjoin version 2 messages use [[https://github.com/bitcoin/bips/blob/master/bip
 
 The Payjoin version 2 protocol takes the following steps:
 
-* The receiver sends their Payjoin Session public key and optional authentication credential according to the [[#enroll-messaging|enroll messaging]] protocol to receive a subdirectory allocation. The receiver may go offline and replay enrollment to come back online.
+* The receiver sends their Payjoin Session public key and optional authentication credential according to the [[#session-initiation|Session initiation]] protocol to receive a Payjoin Session subdirectory. The receiver may go offline and replay Session initiation to come back online.
 * Out of band, the receiver shares a bitcoin URI with the sender, including a pj= query parameter where the subdirectory is the Payjoin Session public key. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5| base64url]] encoding. 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. An ohttp= parameter containing the directory's base64url encoded [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| Oblivious HTTP Key Configuration]] must also be provided.
 * The sender creates a valid version 2 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, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#send-messaging|Original PSBT Request send message]] is sent to the directory's OHTTP Gateway.
 * The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry.
@@ -144,13 +144,13 @@ The Payjoin 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.
 
-====Enroll Messaging====
+====Session Initiation====
 
-Receivers must enroll with a directory to have a subdirectory allocated to them, as follows:
+Receivers must initialize a Payjoin Session on a directory to have a Session subdirectory allocated to them, as follows:
 
-A receiver must first discover the directory's OHTTP gateway Key Configuration via an authenticated bootstrap mechanism before it can enroll 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.
+A receiver must first discover the directory's OHTTP Gateway Key Configuration via an authenticated bootstrap mechanism before it can initialilze 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.
 
-Payjoin Sessions begin by having a receiver send the static public key to the directory via OHTTP, receiving their subdirectory in a base64url encoded directory URL as response. Enrollment may be replayed in case the receiver goes offline and should result in the same response, i.e. it Is idempotent.
+Payjoin Sessions begin by having a receiver send the static public key to the directory via OHTTP, receiving their subdirectory in a base64url encoded directory URL as response. Initiation may be replayed in case the receiver goes offline and should result in the same response, i.e. it Is idempotent.
 
 Optionally, before returning the URI, the receiver may request an authentication token by presenting a message containing only the word Authenticate: , after which the receiver is required to submit an Authenticate:  including the token from the directory out of band. If authentication fails, an error is returned.
 
@@ -179,11 +179,11 @@ The version 2 sender's checklist is largely the same as the [[https://github.com
 
 ===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 HTTP to enrolled subdirectories to support backwards compatible Payjoin version 1 requests.
+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 receiver subdirectory allocated on the directory has one buffer for requests and one for responses. Each buffer updates listeners through awaitable events so that updates are immediately apparent upon client request.
+Each Payjoin Session subdirectory allocated on the directory has one buffer for requests and one for responses. Each buffer updates listeners through awaitable events so that updates are immediately apparent upon client request.
 
 ===Receiver fragment parameters===
 
@@ -259,7 +259,7 @@ The PSBT version 1 protocol was replaced because it was not designed to have inp
 
 ===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 subdirectory to receivers.
+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.
 

From df3bd5239b20a9183d24d27c0d1d46da367a5262 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Mon, 15 Jul 2024 13:00:10 -0400
Subject: [PATCH 32/50] Revise Sequence Diagram

---
 bip-0077.mediawiki | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index a84d4aabd4..69830246c9 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -69,10 +69,10 @@ Key:
 | Receiver |                 | Directory |       | Sender |  | Network |
 +----------+                 +-----------+       +--------+  +---------+
 |                                  |                  |                |
-| Request subdirectory             |                  |                |
+|   Request Session subdirectory   |                  |                |
 +--------------------------------->|                  |                |
 |                                  |                  |                |
-|           subdirectory           |                  |                |
+|       Session subdirectory       |                  |                |
 |<---------------------------------|                  |                |
 |                                  |                  |                |
 |      destination (address,       |                  |                |
@@ -89,7 +89,7 @@ Key:
 |<---------------------------------|                  |                |
 |                                  |                  |                |
 |                                  |                  |                |
-|             Payjoin PSBT         |                  |                |
+|           Payjoin PSBT           |                  |                |
 +--------------------------------->|                  |                |
 |                                  |   Payjoin PSBT   |                |
 |                                  |----------------->|                |

From dc4a9757343a8449ee3c8239db53fbdc180c834b Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Thu, 26 Sep 2024 14:30:35 -0400
Subject: [PATCH 33/50] Spell initialize

---
 bip-0077.mediawiki | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 69830246c9..27d7c7fa86 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -111,7 +111,7 @@ The Payjoin version 2 protocol takes the following steps:
 * The sender creates a valid version 2 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, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#send-messaging|Original PSBT Request send message]] is sent to the directory's OHTTP Gateway.
 * The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry.
 * The request is stored in the subdirectory.
-* Once the receiver is online, it sends [[#receive-messaging|/receive]] requests to await updates from 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 Payjoin PSBT.
+* Once the receiver is online, it sends [[#receive-messaging|/payjoin]] requests to await updates from 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 Payjoin PSBT.
 * The Payjoin PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and sent to the directory's OHTTP Gateway.
 * The directory awaits a request from the sender if it goes offline. Upon request, the directory relays the encrypted Payjoin PSBT.
 * The sender validates the Payjoin PSBT according to [[#senders-payjoin-psbt-checklist|the sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network.
@@ -148,7 +148,7 @@ The Payjoin PSBT MUST NOT:
 
 Receivers must initialize a Payjoin Session on a directory to have a Session subdirectory allocated to them, as follows:
 
-A receiver must first discover the directory's OHTTP Gateway Key Configuration via an authenticated bootstrap mechanism before it can initialilze 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.
+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.
 
 Payjoin Sessions begin by having a receiver send the static public key to the directory via OHTTP, receiving their subdirectory in a base64url encoded directory URL as response. Initiation may be replayed in case the receiver goes offline and should result in the same response, i.e. it Is idempotent.
 

From 87f892dce6146605842d25d4c91bc6412d2f78cd Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Thu, 26 Sep 2024 15:25:39 -0400
Subject: [PATCH 34/50] Update the bip to represent the stable protocol

---
 bip-0077.mediawiki | 42 +++++++++++++++++-------------------------
 1 file changed, 17 insertions(+), 25 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 27d7c7fa86..0ab74b05ee 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -30,11 +30,11 @@ The primary goal of this proposal is to provide a practical coordination mechani
 
 ===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. This protocol also upgrades to [[https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki| PSBT Version 2]] to simplify transaction construction.
+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 Payjoin 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 while using a directory relay without compromising sender or receiver privacy.
+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 Payjoin 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 stealing funds.
+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.
 
@@ -52,9 +52,9 @@ Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP e
 
 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 a public key. This 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. The response message from the directory to the receiver includes the new Session subdirectory payjoin endpoint using the public key as a subdirectory identifier. Once 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]].
+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 encrypted and authenticated 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.
+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.
 
@@ -102,16 +102,14 @@ Key:
 
 ===Payjoin version 2 messaging===
 
-Payjoin version 2 messages use [[https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki| BIP 370: PSBT Version 2]] (PSBTv2) format to facilitate [[#psbt-version-2|PSBT mutation]].
-
 The Payjoin version 2 protocol takes the following steps:
 
 * The receiver sends their Payjoin Session public key and optional authentication credential according to the [[#session-initiation|Session initiation]] protocol to receive a Payjoin Session subdirectory. The receiver may go offline and replay Session initiation to come back online.
-* Out of band, the receiver shares a bitcoin URI with the sender, including a pj= query parameter where the subdirectory is the Payjoin Session public key. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5| base64url]] encoding. 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. An ohttp= parameter containing the directory's base64url encoded [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| Oblivious HTTP Key Configuration]] must also be provided.
-* The sender creates a valid version 2 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, optional sender parameters, and HPKE keys are encrypted and authenticated, and encapsulated in OHTTP. This [[#send-messaging|Original PSBT Request send message]] is sent to the directory's OHTTP Gateway.
+* Out of band, the receiver shares a bitcoin URI with the sender, including a pj= query parameter where the subdirectory is the compressed Payjoin Session public key. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5| base64url]] encoding. 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. An ohttp= fragment parameter containing the directory's base64url encoded [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| Oblivious HTTP Key Configuration]] must also be provided. It should also include an exp= parameter with a Unix timestamp after which the receiver will broadcast the Original PSBT and stop polling the session.
+* 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, and encapsulated in OHTTP. This [[#send-messaging|Original PSBT Request send message]] is made to the directory's OHTTP Gateway.
 * The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry.
 * The request is stored in the subdirectory.
-* Once the receiver is online, it sends [[#receive-messaging|/payjoin]] requests to await updates from 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 Payjoin PSBT.
+* Once the receiver is online, it sends [[#receive-messaging|GET]] 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 Payjoin PSBT.
 * The Payjoin PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and sent to the directory's OHTTP Gateway.
 * The directory awaits a request from the sender if it goes offline. Upon request, the directory relays the encrypted Payjoin PSBT.
 * The sender validates the Payjoin PSBT according to [[#senders-payjoin-psbt-checklist|the sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network.
@@ -120,14 +118,12 @@ The Original PSBT MUST:
 
 * Include complete UTXO data.
 * Be signed.
-* Exclude unnecessary fields such as global xpubs or keypath information. 
-* Set input and output Transaction Modifiable Flags to 1.
+* 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.
-* Set SIGHASH_SINGLE Transaction Modifiable Flags flags to 1.
 
 The Payjoin PSBT MUST:
 
@@ -158,24 +154,24 @@ If a directory is operated by an exchange, it may give out authentication tokens
 
 ====Send Messaging====
 
-The version 2 Original PSBT is serialized in base64, followed by the query parameter string on a new line. This plaintext string is encrypted according to the HPKE using a shared secret derived from a newly generated Payjoin Session keypair 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.
+The Original PSBT is serialized in base64, followed by the query parameter string on a new line. This plaintext string is encrypted according to the HPKE using a shared secret derived from a newly generated Payjoin Session keypair 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.
 
 Upon receipt, the directory's OHTTP Gateway decapsulates the OHTTP request and handles the inner POST request at the Payjoin Session subdirectory endpoint, which stores the HPKE encrypted payload to be forwarded to the receiver. The directory's OHTTP Gateway awaits a request from the receiver to the Payjoin Session subdirectory endpoint and responds with the HPKE encrypted Original PSBT payload acording to OHTTP.
 
 ====Receive Messaging====
 
-The receiver sends a GET request to the path of the subdirectory followed by /receive. This request is encapsulated in OHTTP. 
-The receiver then awaits an OHTTP response from the directory encapsulating a request from the sender with status code 200 OK, or sends 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.
+The receiver sends a GET request to the path of the subdirectory followed by. This request is encapsulated in OHTTP.
+The receiver then awaits an OHTTP response from the directory encapsulating a request from the sender with status code 200 OK, and otherwise 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.
 
-Once an Original PSBT Payload is decrypted and checked according to the [[#receivers-payjoin-psbt-checklist|checklist]], the receiver should respond with a Payjoin PSBT or an error. The receiver encrypts the PSBT according to the HPKE protocol, generating an ephemeral keypair e from which it derives a shared secret ee with the sender's key e from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Payjoin 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 payload is then sent to the directory in an OHTTP request encapsulating the binary payload as a POST message to the subdirectory followed by /receive.
+Once an Original PSBT Payload is decrypted and checked according to the [[#receivers-payjoin-psbt-checklist|checklist]], the receiver should respond with a Payjoin PSBT or an error. The receiver encrypts the PSBT according to the HPKE protocol, generating an ephemeral keypair from which it derives a shared secret with the sender's key e from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Payjoin 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 Payjoin PSBT payload is then sent to the directory in an OHTTP request encapsulating the binary payload as a PUT message to the subdirectory.
 
 ===Receiver's Payjoin PSBT checklist===
 
-Other than requiring PSBTv2, 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]]
+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 Payjoin 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 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.
+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===
 
@@ -196,7 +192,7 @@ Instead of defining new [[https://github.com/bitcoin/bips/blob/master/bip-0021.m
 
 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 https://payjo.in/A_AIjiMHeXGyelsouuwGLELpdzisOfj8eWzjh2OJ3cim#ohttp%3DAQAgF9BeZJPsVQ4dQ-yFmNE_vAzHHD-CGfcRTOGxCngofR8ABAABAAM%26exp%3D1721098849
+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.
 
@@ -253,10 +249,6 @@ This authenticated encryption with additional data [[https://en.wikipedia.org/wi
 
 SHA-256 is considered secure and is necessarily available in bitcoin contexts.
 
-===PSBT Version 2===
-
-The PSBT version 1 protocol was replaced because it was not designed to have inputs and outputs be mutated. Payjoin mutates the PSBT, so BIP 78 uses a workaround where a new PSBT is created by the receiver instead of mutating it. This can cause strange behaviors from signers who don't know where to look to find the scripts that they are accountable for. PSBT version 2 makes mutating a PSBT's inputs and outputs trivial. It also eliminates the transaction finalization step. Receivers who do not understand PSBT version 1 may choose to reject Payjoin version 1 requests and only support PSBT version 2.
-
 ===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.
@@ -281,7 +273,7 @@ Receivers may choose to support version 1 payloads. Version 2 Payjoin URIs for b
 
 ==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 implements an asynchronous payment flow using HTTP using PSBTv1 with encryption and Oblivious HTTP and may be configured to the following independent production relays:
+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]].
 

From 11b1b83db699e8f6f68e708b6e3b1fa258b03e7d Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Thu, 26 Sep 2024 16:49:29 -0400
Subject: [PATCH 35/50] Spell according to Type Checks's job

---
 bip-0077.mediawiki | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 0ab74b05ee..fdf041f80e 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -229,7 +229,7 @@ OHTTP relays can be run as basic HTTP proxies from wallet providers or third par
 
 ===Message Padding===
 
-All cyphertexts 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.
+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===
 

From e44f748f6a273219462a97058a064db0b70d2dab Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Thu, 26 Sep 2024 17:04:46 -0400
Subject: [PATCH 36/50] Mention the format of the ohttp fragment

---
 bip-0077.mediawiki | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index fdf041f80e..9dd9c956f5 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -187,7 +187,7 @@ A major benefit of BIP 78 Payjoin over other coordination mechanisms is its comp
 
 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 public key of the directory's OHTTP Gateway. This parameter is required for version 2 Payjoin URIs.
+* 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.

From f7a5d25b522dcb0304e0f444426403f3dd930462 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Tue, 8 Oct 2024 00:17:58 -0400
Subject: [PATCH 37/50] Reference BIP 78 attack vectors

---
 bip-0077.mediawiki | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 9dd9c956f5..f7ed8b1766 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -251,6 +251,8 @@ 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.

From 3b7be8cf18e60ccf4f516ca02db50c8ba2d1cd22 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Tue, 8 Oct 2024 14:17:47 -0400
Subject: [PATCH 38/50] Remove straggling text

---
 bip-0077.mediawiki | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index f7ed8b1766..5acf1917bf 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -160,7 +160,7 @@ Upon receipt, the directory's OHTTP Gateway decapsulates the OHTTP request and h
 
 ====Receive Messaging====
 
-The receiver sends a GET request to the path of the subdirectory followed by. This request is encapsulated in OHTTP.
+The receiver sends a GET request to the path of the subdirectory. This request is encapsulated in OHTTP.
 The receiver then awaits an OHTTP response from the directory encapsulating a request from the sender with status code 200 OK, and otherwise 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.
 
 Once an Original PSBT Payload is decrypted and checked according to the [[#receivers-payjoin-psbt-checklist|checklist]], the receiver should respond with a Payjoin PSBT or an error. The receiver encrypts the PSBT according to the HPKE protocol, generating an ephemeral keypair from which it derives a shared secret with the sender's key e from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Payjoin 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 Payjoin PSBT payload is then sent to the directory in an OHTTP request encapsulating the binary payload as a PUT message to the subdirectory.

From 66457a011186b0175f7f027d8c226e07e7fd8aa9 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Wed, 9 Oct 2024 01:12:09 -0400
Subject: [PATCH 39/50] Specify authorization mechanism

The specifics of a credential issuance are left out, however
---
 bip-0077.mediawiki | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 5acf1917bf..a7245f6e9b 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -142,15 +142,13 @@ The Payjoin PSBT MUST NOT:
 
 ====Session Initiation====
 
-Receivers must initialize a Payjoin Session on a directory to have a Session subdirectory allocated to them, as follows:
+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.
 
-Payjoin Sessions begin by having a receiver send the static public key to the directory via OHTTP, receiving their subdirectory in a base64url encoded directory URL as response. Initiation may be replayed in case the receiver goes offline and should result in the same response, i.e. it Is idempotent.
+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.
 
-Optionally, before returning the URI, the receiver may request an authentication token by presenting a message containing only the word Authenticate: , after which the receiver is required to submit an Authenticate:  including the token from the directory out of band. If authentication fails, an error is returned.
-
-If a directory is operated by an exchange, it may give out authentication tokens for users of its app, or may require some proof of work out of band. Tokens should be anonymous credentials from the directory describing the parameters of their authorization. Specific credentialing is out of the scope of this proposal.
+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====
 

From c917eab7e8d2c4cd72b50bb6db877a171ffcd037 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Wed, 9 Oct 2024 01:01:27 -0400
Subject: [PATCH 40/50] Use implicit session initialization

---
 bip-0077.mediawiki | 48 +++++++++++++++++++++++-----------------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index a7245f6e9b..7bda249a34 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -69,31 +69,26 @@ Key:
 | Receiver |                 | Directory |       | Sender |  | Network |
 +----------+                 +-----------+       +--------+  +---------+
 |                                  |                  |                |
-|   Request Session subdirectory   |                  |                |
-+--------------------------------->|                  |                |
-|                                  |                  |                |
-|       Session subdirectory       |                  |                |
-|<---------------------------------|                  |                |
 |                                  |                  |                |
 |      destination (address,       |                  |                |
 |        subdirectory)             |                  |                |
 +---------------------------------------------------->|                |
 |                                  |                  |                |
-|      Request Original PSBT       |                  |                |
-+- - - - - - - - - - - - - - - - ->|                  |                |
+|    GET Request Original PSBT     |                  |                |
++- - - - - - - - - - - - - - - - ->|   POST Request   |                |
 |                                  |  Original PSBT   |                |
+|    GET Response Original PSBT    |<-----------------|                |
+|<---------------------------------|   GET Request    |                |
+|                                  |   Payjoin PSBT   |                |
 |                                  |<- - - - - - - - -|                |
 |                                  |                  |                |
 |                                  |                  |                |
-|          Original PSBT           |                  |                |
-|<---------------------------------|                  |                |
 |                                  |                  |                |
-|                                  |                  |                |
-|           Payjoin PSBT           |                  |                |
-+--------------------------------->|                  |                |
+|      POST Payjoin PSBT           |                  |                |
++--------------------------------->|   GET Response   |                |
 |                                  |   Payjoin PSBT   |                |
 |                                  |----------------->|                |
-|                                  |                  |                |
+|                                  |                  |   Broadcast    |
 |                                  |                  |   Payjoin      |
 |                                  |                  +--------------->|
 |                                  |                  |                |
@@ -104,13 +99,13 @@ Key:
 
 The Payjoin version 2 protocol takes the following steps:
 
-* The receiver sends their Payjoin Session public key and optional authentication credential according to the [[#session-initiation|Session initiation]] protocol to receive a Payjoin Session subdirectory. The receiver may go offline and replay Session initiation to come back online.
+* 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 where the subdirectory is the compressed Payjoin Session public key. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5| base64url]] encoding. 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. An ohttp= fragment parameter containing the directory's base64url encoded [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| Oblivious HTTP Key Configuration]] must also be provided. It should also include an exp= parameter with a Unix timestamp after which the receiver will broadcast the Original PSBT and stop polling the session.
-* 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, and encapsulated in OHTTP. This [[#send-messaging|Original PSBT Request send message]] is made to the directory's OHTTP Gateway.
-* The sender continues to replay this request in order to await a response from the directory containing a Payjoin PSBT. It stops after expiry.
+* 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 encapsulats it all as OHTTP. This [[#send-messaging|Original PSBT Request send message]] is made to the directory's OHTTP Gateway.
+* 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 Payjoin PSBT. It stops polling after expiry.
 * The request is stored in the subdirectory.
 * Once the receiver is online, it sends [[#receive-messaging|GET]] 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 Payjoin PSBT.
-* The Payjoin PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and sent to the directory's OHTTP Gateway.
+* The Payjoin PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and POSTed to the directory's OHTTP Gateway.
 * The directory awaits a request from the sender if it goes offline. Upon request, the directory relays the encrypted Payjoin PSBT.
 * The sender validates the Payjoin PSBT according to [[#senders-payjoin-psbt-checklist|the sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network.
 
@@ -152,16 +147,21 @@ If a directory is subject to denial of service attacks, it may require [[https:/
 
 ====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 the HPKE using a shared secret derived from a newly generated Payjoin Session keypair 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.
+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 Payjoin Session subdirectory endpoint, which stores the HPKE encrypted payload to be forwarded to the receiver. The directory's OHTTP Gateway awaits a request from the receiver to the Payjoin Session subdirectory endpoint and responds with the HPKE encrypted Original PSBT payload acording to OHTTP.
+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 receiver's Payjoin Session subdirectory endpoint in order to await a response from the directory containing a Payjoin PSBT. It stops polling after expiry.
 
 ====Receive Messaging====
 
-The receiver sends a GET request to the path of the subdirectory. This request is encapsulated in OHTTP.
-The receiver then awaits an OHTTP response from the directory encapsulating a request from the sender with status code 200 OK, and otherwise 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.
+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 Payjoin PSBT according to the [[#receivers-payjoin-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 Payjoin PSBT.
 
-Once an Original PSBT Payload is decrypted and checked according to the [[#receivers-payjoin-psbt-checklist|checklist]], the receiver should respond with a Payjoin PSBT or an error. The receiver encrypts the PSBT according to the HPKE protocol, generating an ephemeral keypair from which it derives a shared secret with the sender's key e from the payload. It generates a nonce from sufficient randomness, and constructs a ciphertext containing the Payjoin 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 Payjoin PSBT payload is then sent to the directory in an OHTTP request encapsulating the binary payload as a PUT message to the subdirectory.
+The receiver encrypts the Payjoin 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 Payjoin 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 Payjoin 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 Payjoin PSBT checklist===
 
@@ -177,7 +177,7 @@ The Payjoin Directory provides a rendezvous point for sender and receiver to mee
 
 ===Subdirectories===
 
-Each Payjoin Session subdirectory allocated on the directory has one buffer for requests and one for responses. Each buffer updates listeners through awaitable events so that updates are immediately apparent upon client request.
+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===
 
@@ -196,7 +196,7 @@ Using the fragment for Payjoin URI parameters makes for more compact QR codes to
 
 ===Optional sender parameters===
 
-When a Payjoin sender posts an Original PSBT to the receiver, the sender should specify the following HTTP query string 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.
 

From 3046520ebaf481fa77e0e887bbb2be29f1961832 Mon Sep 17 00:00:00 2001
From: Dan Gould 
Date: Wed, 16 Oct 2024 15:27:22 -0400
Subject: [PATCH 41/50] Specify cryptographic handshake based on Noise IK

Co-authored-by: Yuval Kogman 
---
 bip-0077.mediawiki | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 7bda249a34..5034d44402 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -233,7 +233,7 @@ All ciphertexts should be padded to the same length of 7168 bytes to prevent tra
 
 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/NKpsk0/| 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.
+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====
 

From 28f064b98afd4c9138aa4ace51ebf348d3654d23 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Sun, 20 Oct 2024 21:39:40 -0400
Subject: [PATCH 42/50] Add Spacebear's clarifications

Co-authored-by: spacebear 
---
 bip-0077.mediawiki | 46 +++++++++++++++++++++++-----------------------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 5034d44402..e82f110f99 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -32,7 +32,7 @@ The primary goal of this proposal is to provide a practical coordination mechani
 
 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 Payjoin 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.
+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.
 
@@ -79,14 +79,14 @@ Key:
 |                                  |  Original PSBT   |                |
 |    GET Response Original PSBT    |<-----------------|                |
 |<---------------------------------|   GET Request    |                |
-|                                  |   Payjoin PSBT   |                |
+|                                  |  Proposal PSBT   |                |
 |                                  |<- - - - - - - - -|                |
 |                                  |                  |                |
 |                                  |                  |                |
 |                                  |                  |                |
-|      POST Payjoin PSBT           |                  |                |
+|      POST Proposal PSBT          |                  |                |
 +--------------------------------->|   GET Response   |                |
-|                                  |   Payjoin PSBT   |                |
+|                                  |   Proposal PSBT  |                |
 |                                  |----------------->|                |
 |                                  |                  |   Broadcast    |
 |                                  |                  |   Payjoin      |
@@ -100,14 +100,14 @@ Key:
 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 where the subdirectory is the compressed Payjoin Session public key. The key is encoded in [[https://datatracker.ietf.org/doc/html/rfc4648#section-5| base64url]] encoding. 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. An ohttp= fragment parameter containing the directory's base64url encoded [[https://www.ietf.org/rfc/rfc9458.html#name-key-configuration| Oblivious HTTP Key Configuration]] must also be provided. It should also include an exp= parameter with a Unix timestamp after which the receiver will broadcast the Original PSBT and stop polling the session.
-* 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 encapsulats it all as OHTTP. This [[#send-messaging|Original PSBT Request send message]] is made to the directory's OHTTP Gateway.
-* 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 Payjoin PSBT. It stops polling after expiry.
-* The request is stored in the subdirectory.
-* Once the receiver is online, it sends [[#receive-messaging|GET]] 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 Payjoin PSBT.
-* The Payjoin PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and POSTed to the directory's OHTTP Gateway.
-* The directory awaits a request from the sender if it goes offline. Upon request, the directory relays the encrypted Payjoin PSBT.
-* The sender validates the Payjoin PSBT according to [[#senders-payjoin-psbt-checklist|the sender checklist]], signs its inputs and broadcasts the transaction to the Bitcoin network.
+* 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:
 
@@ -120,17 +120,17 @@ The Original PSBT MAY:
 
 * Include outputs unrelated to the sender-receiver transfer for batching purposes.
 
-The Payjoin PSBT MUST:
+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 Payjoin PSBT sender MAY:
+The Proposal PSBT sender MAY:
 
 * Add, remove or modify Original PSBT outputs under the control of the receiver (i.e. not sender change).
 
-The Payjoin PSBT MUST NOT:
+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.
@@ -151,23 +151,23 @@ The Original PSBT is serialized in base64, followed by the query parameter strin
 
 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 receiver's Payjoin Session subdirectory endpoint in order to await a response from the directory containing a Payjoin PSBT. It stops polling after expiry.
+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 Payjoin PSBT according to the [[#receivers-payjoin-psbt-checklist|checklist]].
+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 Payjoin PSBT.
+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 Payjoin 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 Payjoin 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 Payjoin 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.
+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 Payjoin PSBT checklist===
+===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 Payjoin PSBT checklist===
+===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.
 
@@ -255,7 +255,7 @@ Since directories store arbitrary encrypted payloads they are vulnerable to the
 
 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 Payjoin PSBT and wait for a signature once a Payjoin 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.
+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===
 
@@ -269,7 +269,7 @@ The receivers advertise Payjoin capabilities through [[https://github.com/bitcoi
 
 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 Payjoin 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]].
+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==
 

From 915258a925da7061b60c380269a255f1ede3877f Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Sun, 5 Jan 2025 22:04:52 -0500
Subject: [PATCH 43/50] Document subdirectory Short IDs

---
 bip-0077.mediawiki | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index e82f110f99..7355ef7d84 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -52,9 +52,13 @@ Payjoin requests are made using familiar BIP 21 URIs. Instead of a public HTTP e
 
 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]].
+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 checksum [[#short-id| short ID]], is used to identify a store-and-forward Session subdirectory on the Payjoin Directory server and establishes 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 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 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.
+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 using the subdirectory pj= endpoint.
+
+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 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 sender validates the receiver's Proposal PSBT, and if satisfied, signs its inputs and broadcasts the transaction to the Bitcoin network.
 
 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.
 
@@ -100,12 +104,12 @@ Key:
 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]] .
+* Out of band, the receiver shares a bitcoin URI with the sender, including a pj= query parameter. The pj 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 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.
+* The sender polls GET requests to the subdirectory defined by the sender's Payjoin Session public key short ID 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 Proposal PSBT and HPKE keys are encrypted, authenticated, encapsulated in OHTTP, and POSTed to the sender's subdirectory via 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.
 
@@ -141,8 +145,6 @@ Sessions between senders and receivers are established out of band when a receiv
 
 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====
@@ -179,6 +181,14 @@ The Payjoin Directory provides a rendezvous point for sender and receiver to mee
 
 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.
 
+
+====Short ID====
+
+Short IDs are an 8-byte identifier for a Payjoin Session subdirectory. 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 "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.
+
+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) sessions, for which the probability of a random collision with will be less than 1%. The actual number of sessions will of course be (orders of magnitudes) lower given they are short lived. With ~2^21 sessions (loose bound on number of transactions that can be confirmed in 24 hours) the probability is less than 1e-6. These figures are for the existence of a collision in the set, the probability for an individual session to experience a random collision is << 1e-10 in either case.
+
+
 ===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.
@@ -190,7 +200,7 @@ Instead of defining new [[https://github.com/bitcoin/bips/blob/master/bip-0021.m
 
 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
+For example, a properly encoded endpoint URL fragment looks like this bitcoin:tb1q6q6de88mj8qkg0q5lupmpfexwnqjsr4d2gvx2p?amount=0.00666666&pjos=0&pj=HTTPS://PAYJO.IN/TXJCGKTKXLUUZ%23RK1Q0DJS3VVDXWQQTLQ8022QGXSX7ML9PHZ6EDSF6AKEWQG758JPS2EV+OH1QYPM59NK2LXXS4890SUAXXYT25Z2VAPHP0X7YEYCJXGWAG6UG9ZU6NQ+EX1WKV8CEC
 
 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.
 

From 113c2370830c9b31cda7cf0a722c9783fc1b364a Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Sun, 5 Jan 2025 22:07:03 -0500
Subject: [PATCH 44/50] Require uppercase URL

bech32 fragment prefixes are case sensitive, and
alphanumeric mode only works on capital letters.
---
 bip-0077.mediawiki | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 7355ef7d84..f3ee387a70 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -193,7 +193,7 @@ Short IDs are an 8-byte identifier for a Payjoin Session subdirectory. They are
 
 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.
+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. In order to simplify parsing and allow QR encoders to use alphanumeric QR mode, the URL must be uppercased and should come as the last parameter of the URI.
 
 * 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.

From a2b800903b9140dedaff03bc39c3fd8b5966d2c2 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Sun, 5 Jan 2025 22:16:33 -0500
Subject: [PATCH 45/50] Specify bech32 fragment parameter definitions

---
 bip-0077.mediawiki | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index f3ee387a70..9362928547 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -193,12 +193,15 @@ Short IDs are an 8-byte identifier for a Payjoin Session subdirectory. They are
 
 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. In order to simplify parsing and allow QR encoders to use alphanumeric QR mode, the URL must be uppercased and should come as the last parameter of the URI.
+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 # as bech32 prameters separated by an + character. In order to simplify parsing and allow QR encoders to use alphanumeric QR mode, the URL must be uppercased and should come as the last parameter of the URI.
 
-* 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 '#' fragment separator character  must be [[https://datatracker.ietf.org/doc/html/rfc3986| RFC 3986]] percent-encoded as '%23' according to BIP 21.
 
-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.
+Bech32 encoded parameters with no checksum are separated by an + character and prefixed with HRPs according to their role:
+
+* RK: 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.
+* OH: represents the OHTTP Key Configuration of the directory. 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/rfc9458.html#section-3.1| RFC 9458 Key Configuration can be constructed]]. This parameter is required for version 2 Payjoin URIs.
+* EX: 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.
 
 For example, a properly encoded endpoint URL fragment looks like this bitcoin:tb1q6q6de88mj8qkg0q5lupmpfexwnqjsr4d2gvx2p?amount=0.00666666&pjos=0&pj=HTTPS://PAYJO.IN/TXJCGKTKXLUUZ%23RK1Q0DJS3VVDXWQQTLQ8022QGXSX7ML9PHZ6EDSF6AKEWQG758JPS2EV+OH1QYPM59NK2LXXS4890SUAXXYT25Z2VAPHP0X7YEYCJXGWAG6UG9ZU6NQ+EX1WKV8CEC
 

From 952156e52b75821a434e5f33bc483b074ec57f07 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Thu, 16 Jan 2025 22:19:02 -0500
Subject: [PATCH 46/50] Uppercase URL specifically only after subdirectory

---
 bip-0077.mediawiki | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 9362928547..8b0d0b6ba5 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -193,7 +193,7 @@ Short IDs are an 8-byte identifier for a Payjoin Session subdirectory. They are
 
 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 # as bech32 prameters separated by an + character. In order to simplify parsing and allow QR encoders to use alphanumeric QR mode, the URL must be uppercased and should come as the last parameter of the URI.
+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 # as bech32 parameters separated by a + character. In order to simplify parsing and allow QR encoders to use alphanumeric QR mode wherever possible, the pj parameter subdirectory and 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.
 
 The '#' fragment separator character  must be [[https://datatracker.ietf.org/doc/html/rfc3986| RFC 3986]] percent-encoded as '%23' according to BIP 21.
 

From 73941ab3d16b2f432ac25c7c6cbe11790cfb60b9 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Thu, 9 Jan 2025 23:46:08 -0500
Subject: [PATCH 47/50] Note payload uniformity via padding and ellswift

---
 bip-0077.mediawiki | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index 8b0d0b6ba5..e54b0f1f66 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -238,9 +238,16 @@ OHTTP relays can be run as basic HTTP proxies from wallet providers or third par
 
 
 
-===Message Padding===
+===Uniform Payloads===
+
+Encapsulated OHTTP payloads and messages seen by the Payjoin Directory are constructed to be uniform so that 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 which is distinguishable from random bytes but uniform across different encapsulated requests.
+
+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 prepended to the HPKE ciphertext so that the payjoin directory can't distinguish between key material, the ciphertext, and randomness, so that the directory may accomodate new protocols in the future without discrimination.
+
+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.
 
-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===
 

From 4853f5a163c1b44210bbdd27b7182c2cc4bd1f87 Mon Sep 17 00:00:00 2001
From: DanGould 
Date: Fri, 10 Jan 2025 00:04:32 -0500
Subject: [PATCH 48/50] Include Message Byte Representations

This is the most straightforward way to explain the various padding
requirements.
---
 bip-0077.mediawiki | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki
index e54b0f1f66..a9dab1bbc2 100644
--- a/bip-0077.mediawiki
+++ b/bip-0077.mediawiki
@@ -248,6 +248,38 @@ HPKE message payloads are padded to 7168 bytes. Elligator swift is used to encod
 
 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.
 
+====Message Byte Representations====
+
+
+OHTTP Encapsulated Message Byte Representation (8192 bytes total)
++-----------------------------------------------------------------------------------+
+| Uncompressed Public Key |  AEAD Tag  | OHTTP Header |   Padded BHTTP Request      |
+|       (65 bytes)        | (16 bytes) |  (7 bytes)   | (8104 bytes = 8192-65-16-7) |
++-----------------------------------------------------------------------------------+
+
+ +
+Message A Byte Representation (7168 bytes total)
++---------------------------------------------------------------------------------------+
+| ElligatorSwift |                             Ciphertext                               |
+|   (64 bytes)   |                            (7104 bytes)                              |
+|                |----------------------------------------------------------------------|
+|                |    Reply Public Key   |         Padded Plaintext        |  AEAD Tag  |
+|                |       (33 bytes)      |   (7055 bytes = 7168-64-33-16)  | (16 bytes) |
++---------------------------------------------------------------------------------------+
+
+ +
+Mesage B Byte Representation (7168 bytes total)
++---------------------------------------------------------------------------------------+
+| ElligatorSwift |                             Ciphertext                               |
+|   (64 bytes)   |                            (7104 bytes)                              |
+|                |----------------------------------------------------------------------|
+|                |           Padded Plaintext                              |  AEAD Tag  |
+|                |       (7088 bytes = 7168-64-16)                         | (16 bytes) |
++---------------------------------------------------------------------------------------+
+
+ ===Secp256k1 Hybrid Public Key Encryption=== From 69ae3f1a066b7d7e09ba1eca552b27d3c140ff1d Mon Sep 17 00:00:00 2001 From: DanGould Date: Fri, 24 Jan 2025 15:39:40 -0500 Subject: [PATCH 49/50] Document HPKE `info` strings --- bip-0077.mediawiki | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index a9dab1bbc2..04cfb713c2 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -280,6 +280,13 @@ Mesage B Byte Representation (7168 bytes total) +---------------------------------------------------------------------------------------+
+The HPKE info strings used for message encryption are: +* Message A: PjV2MsgA (Original PSBT Request) +* Message B: PjV2MsgB (Proposal PSBT Response) + +These info strings are used as the application-specific info parameter during HPKE encryption to bind the ciphertext +to its specific role in the protocol. + ===Secp256k1 Hybrid Public Key Encryption=== From 799e8c145da0304d847abfe59bd2311a1cf78968 Mon Sep 17 00:00:00 2001 From: DanGould Date: Fri, 24 Jan 2025 15:56:05 -0500 Subject: [PATCH 50/50] Truncate lines to 120 characters --- bip-0077.mediawiki | 396 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 305 insertions(+), 91 deletions(-) diff --git a/bip-0077.mediawiki b/bip-0077.mediawiki index 04cfb713c2..386312eff9 100644 --- a/bip-0077.mediawiki +++ b/bip-0077.mediawiki @@ -12,7 +12,13 @@ ==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. +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== @@ -20,52 +26,113 @@ 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. +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. +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. +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. +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. +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. +[[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. +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. +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 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 checksum [[#short-id| short ID]], is used to identify a store-and-forward Session subdirectory on the Payjoin Directory server and establishes 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 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 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]]. +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 +checksum [[#short-id| short ID]], is used to identify a store-and-forward Session subdirectory on the Payjoin +Directory server and establishes 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 +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 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 using the subdirectory pj= endpoint. +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 using the subdirectory pj= +endpoint. -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 the sender's reply key shared in their payload along with their original PSBT. +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 +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 sender validates the receiver's Proposal PSBT, and if satisfied, signs its inputs and broadcasts the transaction to the Bitcoin network. +The sender will be long polling this second subdirectory 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 +transaction to the Bitcoin network. -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. +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: 
+Key:
 |-----> Single transmission
 |- - -> Polled transmission
 
@@ -104,14 +171,33 @@ Key:
 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 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 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 short ID 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 sender's subdirectory via 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.
+* Out of band, the receiver shares a bitcoin URI with the sender, including a pj= query parameter.
+The pj 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
+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 short
+ID 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 sender's subdirectory via 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:
 
@@ -136,82 +222,150 @@ The Proposal PSBT sender MAY:
 
 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.
+* 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.
+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.
+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.
 
-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.
+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.
+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.
+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.
+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.
+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]].
+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 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.
+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.
+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.
+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.
+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.
-
+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.
 
 ====Short ID====
 
-Short IDs are an 8-byte identifier for a Payjoin Session subdirectory. 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 "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.
-
-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) sessions, for which the probability of a random collision with will be less than 1%. The actual number of sessions will of course be (orders of magnitudes) lower given they are short lived. With ~2^21 sessions (loose bound on number of transactions that can be confirmed in 24 hours) the probability is less than 1e-6. These figures are for the existence of a collision in the set, the probability for an individual session to experience a random collision is << 1e-10 in either case.
+Short IDs are an 8-byte identifier for a Payjoin Session subdirectory. 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
+"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.
 
+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)
+sessions, for which the probability of a random collision with will be less than 1%. The actual number of
+sessions will of course be (orders of magnitudes) lower given they are short lived. With ~2^21 sessions (loose
+bound on number of transactions that can be confirmed in 24 hours) the probability is less than 1e-6. These
+figures are for the existence of a collision in the set, the probability for an individual session to
+experience a random collision is << 1e-10 in either case.
 
 ===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 # as bech32 parameters separated by a + character. In order to simplify parsing and allow QR encoders to use alphanumeric QR mode wherever possible, the pj parameter subdirectory and 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.
-
-The '#' fragment separator character  must be [[https://datatracker.ietf.org/doc/html/rfc3986| RFC 3986]] percent-encoded as '%23' according to BIP 21.
-
-Bech32 encoded parameters with no checksum are separated by an + character and prefixed with HRPs according to their role:
-
-* RK: 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.
-* OH: represents the OHTTP Key Configuration of the directory. 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/rfc9458.html#section-3.1| RFC 9458 Key Configuration can be constructed]]. This parameter is required for version 2 Payjoin URIs.
-* EX: 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.
-
-For example, a properly encoded endpoint URL fragment looks like this bitcoin:tb1q6q6de88mj8qkg0q5lupmpfexwnqjsr4d2gvx2p?amount=0.00666666&pjos=0&pj=HTTPS://PAYJO.IN/TXJCGKTKXLUUZ%23RK1Q0DJS3VVDXWQQTLQ8022QGXSX7ML9PHZ6EDSF6AKEWQG758JPS2EV+OH1QYPM59NK2LXXS4890SUAXXYT25Z2VAPHP0X7YEYCJXGWAG6UG9ZU6NQ+EX1WKV8CEC
-
-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.
+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
+# as bech32 parameters separated by a + character. In order to simplify parsing and
+allow QR encoders to use alphanumeric QR mode wherever possible, the pj parameter subdirectory and
+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.
+
+The '#' fragment separator character must be [[https://datatracker.ietf.org/doc/html/rfc3986| RFC 3986]]
+percent-encoded as '%23' according to BIP 21.
+
+Bech32 encoded parameters with no checksum are separated by an + character and prefixed with HRPs
+according to their role:
+
+* RK: 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.
+* OH: represents the OHTTP Key Configuration of the directory. 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/
+rfc9458.html#section-3.1| RFC 9458 Key Configuration can be constructed]]. This parameter is required for
+version 2 Payjoin URIs.
+* EX: 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.
+
+For example, a properly encoded endpoint URL fragment looks like this bitcoin:tb1q6q6de88mj8qkg0q5lupmpfex
+wnqjsr4d2gvx2p?amount=0.00666666&pjos=0&pj=HTTPS://PAYJO.IN/TXJCGKTKXLUUZ%23RK1Q0DJS3VVDXWQQTLQ8022QGXSX7ML9PHZ
+6EDSF6AKEWQG758JPS2EV+OH1QYPM59NK2LXXS4890SUAXXYT25Z2VAPHP0X7YEYCJXGWAG6UG9ZU6NQ+EX1WKV8CEC
+
+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:
+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.
+* 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.
 
@@ -219,17 +373,27 @@ BIP 78's optional query parameters are also valid as version 2 parameters.
 
 ===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 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=.
+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.
+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 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.
 
@@ -237,16 +401,23 @@ OHTTP relays can be run as basic HTTP proxies from wallet providers or third par
 
 
 
-
 ===Uniform Payloads===
 
-Encapsulated OHTTP payloads and messages seen by the Payjoin Directory are constructed to be uniform so that 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 which is distinguishable from random bytes but uniform across different encapsulated requests.
+Encapsulated OHTTP payloads and messages seen by the Payjoin Directory are constructed to be uniform so that
+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
+which is distinguishable from random bytes but uniform across different encapsulated requests.
 
 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 prepended to the HPKE ciphertext so that the payjoin directory can't distinguish between key material, the ciphertext, and randomness, so that the directory may accomodate new protocols in the future without discrimination.
+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
+ciphertext, and randomness, so that the directory may accomodate new protocols in the future without
+discrimination.
 
-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.
+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.
 
 ====Message Byte Representations====
 
@@ -284,23 +455,35 @@ The HPKE info strings used for message encryption are:
 * Message A: PjV2MsgA (Original PSBT Request)
 * Message B: PjV2MsgB (Proposal PSBT Response)
 
-These info strings are used as the application-specific info parameter during HPKE encryption to bind the ciphertext
-to its specific role in the protocol.
-
+These info strings are used as the application-specific info parameter during HPKE encryption to bind the
+ciphertext to its specific role in the protocol.
 
 ===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.
+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.
+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.
+[[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.
+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====
 
@@ -308,32 +491,63 @@ 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.
+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 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.
+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.
+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.
+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.
+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]].
+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.
+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]].
+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:
+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]].
+An independent Oblivious HTTP relay is run by [[https://www.bobspaces.net| BOB Spaces]] at [[https://pj.
+bobspacebkk.com]].