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