From 970603bbc62f29ce9fa0e7d4bc5375170174920f Mon Sep 17 00:00:00 2001 From: DanGould Date: Sun, 21 Jul 2024 18:36:57 -0400 Subject: [PATCH] Update How it Works --- .../{v1.md => payjoin-v1-bip-78.md} | 24 +++---- docs/how-it-works/payjoin-v2-bip-77.md | 71 +++++++++++++++++++ docs/how-it-works/v2.md | 66 ----------------- 3 files changed, 83 insertions(+), 78 deletions(-) rename docs/how-it-works/{v1.md => payjoin-v1-bip-78.md} (58%) create mode 100644 docs/how-it-works/payjoin-v2-bip-77.md delete mode 100644 docs/how-it-works/v2.md diff --git a/docs/how-it-works/v1.md b/docs/how-it-works/payjoin-v1-bip-78.md similarity index 58% rename from docs/how-it-works/v1.md rename to docs/how-it-works/payjoin-v1-bip-78.md index 32dd84e..f12b88c 100644 --- a/docs/how-it-works/v1.md +++ b/docs/how-it-works/payjoin-v1-bip-78.md @@ -1,31 +1,31 @@ --- sidebar_position: 2 -title: Payjoin v1 (BIP 78) +title: Payjoin V1 (BIP 78) description: The initial payjoin flow --- :::warning -This version will be deprecated in favor of [Payjoin v2](./v2.md). However, everything defined here is backward-compatible and relevant to v2, so read on! +This version will be deprecated in favor of [Payjoin version 2](./payjoin-v2-bip-77.md). However, everything defined here is backward-compatible and relevant to v2, so read on! ::: ### Motivation -The initial payjoin specification as defined in [BIP 78](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki) was designed to solve 2 problems for the sender (Alice) and receiver (Bob) of a given transaction: +The initial payjoin specification as defined in [BIP 78](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki) was designed to solve two problems for the sender (Alice) and receiver (Bob) of a given transaction: - The receiver misses an opportunity to **consolidate UTXOs** or **make a payment**. -- The sender has privacy leaks due to heuristics about typical transactions. +- The sender leaks privacy due to heuristics about typical transactions. In most scenarios today, the sender signs a transaction containing _only_ her UTXOs and broadcasts it to the network. This pattern has led to several heuristics used to erode the privacy of those in the transaction and the network: - **Common input ownership heuristic**: The assumption that all inputs belong to the sender. -- **Change identification from scriptPubKey**: The assumption that if all inputs spend from the same [scriptPubKey](todo) type (P2SH, P2PKH, P2TR, etc), then the change output is likely to have the same scriptPubKey too (since all the inputs belong to the sender, the output with the matching scriptPubKey is likely also the sender's). +- **Change identification from scriptPubKey**: The assumption that if all inputs spend from the same [scriptPubKey](https://river.com/learn/terms/s/scriptpubkey/) type (P2SH, P2PKH, P2TR, etc), then the change output is likely to have the same scriptPubKey too (since all the inputs belong to the sender, the output with the matching scriptPubKey is likely also the sender's). - **Change identification from round amount**: The assumption that the receiver gets the "round amount" (i.e. 0.3 instead of 0.354323...), since it's more natural for him to ask for payment in round amounts. The idea was to allow the receiver to consolidate UTXOs and/or batch payments during the sender's transaction to them (saving fees), and for the sender to invalidate the three heuristics above. -Notably, payjoin transactions enhance the _efficiency_ of the network by reducing the number of transactions and the _privacy_ of the network by invalidating the reliability of the three heuristics used to track users. +Notably, payjoin transactions enhance the _efficiency_ of the network by reducing the number of transactions and preserve the _privacy_ of the network by invalidating the reliability of the three heuristics used to track users. As Adam Gibson has noted, if some relatively small uptick in payjoin usage was observed, it would cast doubt on _all_ transactions, [even for those who don't payjoin](https://reyify.com/blog/payjoin#:~:text=Now%2C%20here%27s%20the,a%20privacy%20advantage!). @@ -35,9 +35,9 @@ BIP 78 defines the following steps for payjoin: 1. The receiver of the payment presents a [BIP 21 URI](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki) to the sender with a parameter `pj=` describing a payjoin endpoint. - Example: `bitcoin:?pj=` -2. The sender creates a signed, finalized PSBT with witness UTXO or previous transactions of the inputs. We call this PSBT the `original`. -3. The receiver replies back with a signed PSBT containing his own signed inputs/outputs and those of the sender. We call this PSBT `Payjoin proposal`. -4. The sender verifies the proposal, re-signs his inputs and broadcasts the transaction to the Bitcoin network. We call this transaction `Payjoin transaction`. +2. The sender creates a signed, finalized PSBT with witness UTXO or previous transactions of the inputs. This is called the `Original PSBT`. +3. The receiver replies back with a signed PSBT containing his own signed inputs/outputs and those of the sender. This is called the `Payjoin Proposal PSBT`. +4. The sender verifies the proposal, re-signs his inputs and broadcasts the transaction to the Bitcoin network. This is called the `Payjoin transaction`. ![Payjoin v1 Flow](./img/v1.png) @@ -45,15 +45,15 @@ BIP 78 defines the following steps for payjoin: The spec defines a few BIP 21 parameters for payjoin: -- `pj=`: The receiver's http(s) endpoint which tells the sender where to POST the original PSBT to. +- `pj=`: The receiver's HTTP(S) endpoint which tells the sender where to POST the original PSBT to. - `pjos=0`: Signal to the sender that they MUST disallow [output substitution](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#payment-output-substitution) (the receiver's ability the modify the outputs. This should be set on unsecured servers to disallow the possibility of the receiver's funds being stolen. See the [full spec](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki) for the full list of available parameters ### Drawbacks -One of the primary drawbacks of payjoin v1 is the requirement of a server for the receiver. This means that a) the funds received are kept in a hot wallet, and b) the server must be online at the time of payment receipt, which in practice means the server will likely need to be always-online. While this is probably fine for businesses, this is a significant barrier to individuals using payjoin. Thankfully, we can do better. +One of the primary drawbacks of Payjoin v1 is that it requires synchronous communication and therefore requires the receiver to host a server. This means that a) the funds received are kept in a hot wallet, and b) the server must be online at the time of payment receipt, which in practice means the server will need to stay perpetually online. While this is probably fine for businesses, it poses a significant barrier to adoption. Thankfully, a better solution exists in [Payjoin version 2](./payjoin-v2-bip-77.md). ### Next Steps -Check out [BIP 78](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki) to see the full payjoin v1 spec. In the next section, we'll learn how payjoin can be made _serverless_ and _asynchronous_ in version 2. +Check out [BIP 78](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki) to see the full Payjoin v1 spec. In the next section, we'll learn how Payjoin can be made _asynchronous_ by removing the requirement for a receiver-hosted server in version 2. diff --git a/docs/how-it-works/payjoin-v2-bip-77.md b/docs/how-it-works/payjoin-v2-bip-77.md new file mode 100644 index 0000000..ef170c2 --- /dev/null +++ b/docs/how-it-works/payjoin-v2-bip-77.md @@ -0,0 +1,71 @@ +--- +sidebar_position: 4 +title: Payjoin V2 (BIP 77) +description: Serverless, asynchronous payjoin +--- + +:::note + +BIP 77 is still a draft BIP. Use at your own risk! + +::: + +### Motivation + +Payjoin version 2 ([BIP 77](https://github.com/bitcoin/bips/blob/bc3123e1dab1c5b08d6f934b11b4d741107ac386/bip-0077.mediawiki)) is a draft BIP designed to improve on the limitations of version 1. In version 1, a receiver was required to host a server from which to receive requests from a sender as well as to modify the **Original PSBT** from the sender into a **Payjoin PSBT**. + +Payjoin v2 eliminates this receiver requirement by outsourcing the server hosting to an untrusted third party. This "Payjoin Directory" server is dead simple and has one task — store pending payments from the sender, and forward them to and from the receiver when the other party comes back online. These Payjoin payloads are small, ephemeral, and encrypted, so a malicious directory cannot snoop on or forge message contents. + +To make this work, in lieu of hosting a server themselves, the receiver starts a session assigned a _subdirectory_ which will store and forward the encrypted payjoin payloads between the sender and receiver. + +That's all well and good, but what about the IP address metadata being sent to the payjoin directory? After all, even if the untrusted directory couldn't see the plaintext transaction data, couldn't it see the sender and receiver's IP addresses? Without further protection yes it could, but Payjoin v2 makes use of a novel protocol called [Oblivious HTTP](https://www.fastly.com/blog/enabling-privacy-on-the-internet-with-oblivious-http) (OHTTP) to strip client-identifying metadata from the request before it reaches the directory. + +Aside from these two changes in the means of communicating the transaction, the v2 protocol takes on the same shape as v1, and is even backwards-compatible. + +Payjoin v2 removes barriers to adoption by eliminating the need for the sender and receiver to be online at the same time, or for either to ever run any servers themselves. + +### Protocol + +![Payjoin V2 Flow](./img/v2.png) + +:::info + +All requests made to the directory by the sender or receiver are done using OHTTP, so that the directory doesn't know any of their identifying metadata. OHTTP is explained below. + +::: + +At a high level (and omitting some important detail), a Payjoin v2 transaction takes the following steps: + +- **Receiver**: Sends their payjoin session pubkey to the directory to initialize a session at a new subdirectory. +- **Receiver**: Out of band, the receiver shares a [Bitcoin URI](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki) with the sender including a `pj` query parameter itself containing an HTTP URL to the subdirectory. The `pj` URL fragment includes an `ohttp` parameter containing the directory's public key. +- **Sender**: Creates an **Original PSBT** and sends it to the directory alongside Hybrid Public Key Encryption (HPKE) keys to establish end-to-end encryption between sender and receiver. +- **Sender**: Continues to [long poll](https://javascript.info/long-polling) this request in order to await a response from the directory containing a `Payjoin PSBT`. It stops after a designated expiration time. +- The encrypted request is stored in the **subdirectory**. +- **Receiver**: 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 [the receiver checklist](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-original-psbt-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` is encrypted, encapsulated in OHTTP, and sent to the directory's OHTTP Gateway. +- **Sender**: The sender awaits a `Payjoin PSBT` response from the receiver, polling until the response is available. +- **Sender**: The sender validates the `Payjoin PSBT` according to [the sender checklist](https://github.com/bitcoin/bips/blob/bc3123e1dab1c5b08d6f934b11b4d741107ac386/bip-0077.mediawiki#senders-payjoin-psbt-checklist), signs its inputs and broadcasts the transaction to the Bitcoin network. + +Each message between Sender/Receiver client and Directory happens over OHTTP to protect metadata. + +### Oblivous HTTP (OHTTP) + +[Oblivious HTTP](https://www.ietf.org/rfc/rfc9458.html) works by separating knowledge of the client's IP address metadata the request contents. There are four actors in the OHTTP architecture: + +- Client +- Relay +- Gateway +- Target + +The _Client_ is trying to make a request to the _Target_ such that the Target can only see the request contents and not the Client's metadata. + +![OHTTP](./img/ohttp.png) + +1. The Client encapsulates and encrypts a request intended for the target and sends it to the relay. +2. The Relay receives the encapsulated request and can see client metadata and HTTP headers. It strips them, and forwards the encapsulated request to the Gateway. This means that the relay knows identifying details about the Client. The encapsulated request is encrypted with a key the Relay doesn't have, so the Relay doesn't know what data has been sent to the Client, only the metadata. +3. The Gateway receives the anonymized version of the Client's request from the Relay, decrypts and decapsulates it, and then forwards it to the Target. The Gateway doesn't know identifying metadata about the Client. +4. The Target receives the request as normal HTTP without learning any metadata about the Client. It processes the request, and sends it back to the Gateway. The Gateway re-encapsulates/encrypts the response and sends it back through the Relay to the Client. + +That is to say Payjoin v2 enables all of the functionality of Payjoin v1 without the client burdens. The most costly operations are outsourced to an untrusted third party so that even a mobile device can do Payjoin. + +To learn more about Payjoin v2, dive into [BIP 77](https://github.com/bitcoin/bips/pull/1483) or complete one of the [tutorials](/tutorials). diff --git a/docs/how-it-works/v2.md b/docs/how-it-works/v2.md deleted file mode 100644 index 68ca9ca..0000000 --- a/docs/how-it-works/v2.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -sidebar_position: 4 -title: Payjoin v2 (BIP 77) -description: Serverless, asynchronous payjoin ---- - -:::note - -BIP 77 is still a draft BIP. Use at your own risk! - -::: - -### Motivation - -Payjoin version 2 ([BIP 77](https://github.com/bitcoin/bips/blob/bc3123e1dab1c5b08d6f934b11b4d741107ac386/bip-0077.mediawiki)) is a draft BIP designed to improve on the primary limitations of version 1. In version 1, a receiver was required to have a server from which to send the [BIP 21 URI](todo) as well as modify the **Original PSBT** from the sender into a **Payjoin PSBT**. - -Payjoin v2 eliminates this requirement by outsourcing the server called a _directory_ to an untrusted third party. This server is dead simple and has one task -- store pending payments from the sender, and forward them to the receiver when they come back online. These in-flight payment messages are small, ephemeral, and encrypted, so a malicious directory cannot snoop on or forge message contents. - -To make this work, in lieu of hosting a server themselves, the receiver starts a session with the directory to request a _subdirectory_ which will contain the encrypted payment PSBTs between the sender and receiver. - -That's all well and good, but what about the metadata being sent to the payjoin directory? After all, even if the untrusted directory couldn't see the actual transaction data, couldn't they see the sender and receiver's IP addresses and other metadata? Typically, yes, but payjoin v2 makes use of a novel protocol called [_Oblivious HTTP_](https://www.fastly.com/blog/enabling-privacy-on-the-internet-with-oblivious-http) to strip client identifying metadata from the request before it reaches the directory. - -Aside from these two changes in the means of communicating the transaction, the protocol remains largely the same as v1. V2 is also backward-compatible with v1. - -Payjoin v2 improves upon the ease-of-use by eliminating the need for the sender and receiver to be online at the same time, or for either to ever run any servers to do so. Unlike v1, it is both serverless and asynchronous, removing the primary barriers to adoption that v1 faced. - -### Protocol - -![Payjoin V2 Flow](./img/v2.png) - -:::info - -All requests made to the directory by the sender or receiver are done using OHTTP, so that the directory doesn't know any of their identifying metadata. OHTTP is explained below. - -::: - -At a high level (and omitting some important detail), a payjoin v2 transaction takes the following steps: - -- **Receiver**: Sends their payjoin pubkey to the directory to _enroll_ for a subdirectory on it. -- **Receiver**: Out of band, the receiver of the payment shares a bitcoin URI with the sender including a `pj=` query parameter with the subdirectory. An `ohttp=` parameter containing the directory's public key should also be provided. -- **Sender**: Creates an **Original PSBT** and sends it to the directory. -- **Sender**: Continues to replay this request in order to await a response from the directory containing a `Payjoin PSBT`. It stops after a designated expiration time. -- 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 [the receiver checklist](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki#receivers-original-psbt-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 [the sender checklist](https://github.com/bitcoin/bips/blob/bc3123e1dab1c5b08d6f934b11b4d741107ac386/bip-0077.mediawiki#senders-payjoin-psbt-checklist), signs its inputs and broadcasts the transaction to the Bitcoin network. - -### OHTTP - -[Oblivious HTTP](https://www.fastly.com/blog/enabling-privacy-on-the-internet-with-oblivious-http) works by separating who can see the client's metadata from who can see the actual request. There are four layers to the OHTTP architecture: - -- Client -- Relay -- Gateway -- Target - The _client_ is trying to make a request to the _target_ in such a way that the target can only see the actual request, not the client's metadata. - -![OHTTP](./img/ohttp.png) - -1. The Client encapsulates and encrypts a request intended for the target and sends it to the relay. -2. The Relay receives the encapsulated request and can see client metadata and HTTP headers, strips them, and sends the encapsulated request to the Gateway. This means that the relay knows identifying details about the Client. The encapsulated request is encrypted with a key the Relay doesn't have, so the Relay doesn't know what data has been sent to the Client, only the metadata. -3. The Gateway receives the anonymized version of the Client's request from the Relay, decrypts and de-encapsulates it, and then forwards it to the Target. The Gateway doesn't know identifying information about the Client. -4. The Target receives the request as a normal HTTP request without knowing any metadata about the Client, processes the request, and sends it back to the Gateway. The Gateway re-encapsulates/encrypts the response and sends it back through the Relay to the Client. - -To learn more about payjoin v2, dive into [BIP 77](https://github.com/bitcoin/bips/blob/bc3123e1dab1c5b08d6f934b11b4d741107ac386/bip-0077.mediawiki) or complete one of the tutorials!